package com.yuxue.easypr.core; import static com.yuxue.easypr.core.CoreFunc.getPlateType; import static org.bytedeco.javacpp.opencv_core.CV_32F; import static org.bytedeco.javacpp.opencv_core.countNonZero; import static org.bytedeco.javacpp.opencv_imgproc.CV_CHAIN_APPROX_NONE; import static org.bytedeco.javacpp.opencv_imgproc.CV_RETR_EXTERNAL; import static org.bytedeco.javacpp.opencv_imgproc.CV_RGB2GRAY; import static org.bytedeco.javacpp.opencv_imgproc.CV_THRESH_BINARY; import static org.bytedeco.javacpp.opencv_imgproc.CV_THRESH_BINARY_INV; import static org.bytedeco.javacpp.opencv_imgproc.CV_THRESH_OTSU; import static org.bytedeco.javacpp.opencv_imgproc.INTER_LINEAR; import static org.bytedeco.javacpp.opencv_imgproc.boundingRect; import static org.bytedeco.javacpp.opencv_imgproc.cvtColor; import static org.bytedeco.javacpp.opencv_imgproc.findContours; import static org.bytedeco.javacpp.opencv_imgproc.resize; import static org.bytedeco.javacpp.opencv_imgproc.threshold; import static org.bytedeco.javacpp.opencv_imgproc.warpAffine; import java.util.Vector; import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.Mat; import org.bytedeco.javacpp.opencv_core.MatVector; import org.bytedeco.javacpp.opencv_core.Rect; import org.bytedeco.javacpp.opencv_core.Scalar; import org.bytedeco.javacpp.opencv_core.Size; import org.bytedeco.javacpp.opencv_imgcodecs; import com.yuxue.enumtype.PlateColor; import com.yuxue.util.Convert; /** * 字符分割 * @author yuxue * @date 2020-04-28 09:45 */ public class CharsSegment { // preprocessChar所用常量 final static int CHAR_SIZE = 20; final static int HORIZONTAL = 1; final static int VERTICAL = 0; final static int DEFAULT_LIUDING_SIZE = 7; final static int DEFAULT_MAT_WIDTH = 136; final static int DEFAULT_COLORTHRESHOLD = 150; final static float DEFAULT_BLUEPERCEMT = 0.3f; final static float DEFAULT_WHITEPERCEMT = 0.1f; private int liuDingSize = DEFAULT_LIUDING_SIZE; private int theMatWidth = DEFAULT_MAT_WIDTH; private int colorThreshold = DEFAULT_COLORTHRESHOLD; private float bluePercent = DEFAULT_BLUEPERCEMT; private float whitePercent = DEFAULT_WHITEPERCEMT; private boolean isDebug = true; /** * 字符分割 * * @param input * @param resultVec * @return
* 计算每行元素的阶跃数,如果小于X认为是柳丁,将此行全部填0(涂黑), X可根据实际调整
*
* @param img
* @return
*/
private Mat clearLiuDing(Mat img) {
final int x = this.liuDingSize;
Mat jump = Mat.zeros(1, img.rows(), CV_32F).asMat();
for (int i = 0; i < img.rows(); i++) {
int jumpCount = 0;
for (int j = 0; j < img.cols() - 1; j++) {
if (img.ptr(i, j).get() != img.ptr(i, j + 1).get())
jumpCount++;
}
jump.ptr(i).put(Convert.getBytes((float) jumpCount));
}
for (int i = 0; i < img.rows(); i++) {
if (Convert.toFloat(jump.ptr(i)) <= x) {
for (int j = 0; j < img.cols(); j++) {
img.ptr(i, j).put((byte) 0);
}
}
}
return img;
}
/**
* 根据特殊车牌来构造猜测中文字符的位置和大小
*
* @param rectSpe
* @return
*/
private Rect GetChineseRect(final Rect rectSpe) {
int height = rectSpe.height();
float newwidth = rectSpe.width() * 1.15f;
int x = rectSpe.x();
int y = rectSpe.y();
int newx = x - (int) (newwidth * 1.15);
newx = Math.max(newx, 0);
Rect a = new Rect(newx, y, (int) newwidth, height);
return a;
}
/**
* 找出指示城市的字符的Rect,例如苏A7003X,就是A的位置
* 之所以选择城市的字符位置,是因为该位置不管什么字母,占用的宽度跟高度的差不多,能大大提高位置的准确性
* @param vecRect
* @return
*/
private int GetSpecificRect(final Vector
*
*
* @param vecRect
* @param outRect
* @param specIndex
* @return
*/
private int RebuildRect(final Vector