Java基於opencv實現圖像數字識別(五)—投影法分割字符
水平投影法
1、水平投影法就是先用一個數組統計出圖像每行黑色像素點的個數(二值化的圖像);
2、選出一個最優的閥值,根據比這個閥值大或小,用一個數組記錄相應Y軸的坐標;
3、因為是水平切割我們只需要Y軸的切割點即可,寬度默認圖像的寬,高度可以用相鄰的切割點相減得到;
4、優化切割點,把切割點靠近的都清除掉
5、設置感應區的區域,切割圖片
垂直投影法和水平投影法類似,對比思考一下
因為我做的是表格的切割,你如果想實現驗證碼的切割,或者其他的類比這個,我想也是很容易實現的
我們先看一下,效果,還是很不錯的
水平切割代碼
// 圖像切割,水平投影法切割
public List<Mat> cutImgX() {
int i, j;
int nWidth = getWidth(), nHeight = getHeight();
int[] xNum = new int[nHeight], cNum;
int average = 0;// 記錄像素的平均值
// 統計出每行黑色像素點的個數
for (i = 0; i < nHeight; i++) {
for (j = 0; j < nWidth; j++) {
if (getPixel(i, j) == BLACK) {
xNum[i]++;
}
}
}
// 經過測試這樣得到的平均值最優
cNum = Arrays.copyOf(xNum, xNum.length);
Arrays.sort(cNum);
for (i = 31 * nHeight / 32; i < nHeight; i++) {
average += cNum[i];
}
average /= (nHeight / 32);
// 把需要切割的y點都存到cutY中
List<Integer> cutY = new ArrayList<Integer>();
for (i = 0; i < nHeight; i++) {
if (xNum[i] > average) {
cutY.add(i);
}
}
// 優化cutY把
if (cutY.size() != 0) {
int temp = cutY.get(cutY.size() - 1);
// 因為線條有粗細,優化cutY
for (i = cutY.size() - 2; i >= 0; i--) {
int k = temp - cutY.get(i);
if (k <= 8) {
cutY.remove(i);
} else {
temp = cutY.get(i);
}
}
}
// 把切割的圖片都保存到YMat中
List<Mat> YMat = new ArrayList<Mat>();
for (i = 1; i < cutY.size(); i++) {
// 設置感興趣的區域
int startY = cutY.get(i - 1);
int height = cutY.get(i) - startY;
Mat temp = new Mat(mat, new Rect(0, startY, nWidth, height));
Mat t = new Mat();
temp.copyTo(t);
YMat.add(t);
}
return YMat;
}
垂直投影法
// 圖像切割,垂直投影法切割
public List<Mat> cutImgY() {
int i, j;
int nWidth = getWidth(), nHeight = getHeight();
int[] xNum = new int[nWidth], cNum;
int average = 0;// 記錄像素的平均值
// 統計出每列黑色像素點的個數
for (i = 0; i < nWidth; i++) {
for (j = 0; j < nHeight; j++) {
if (getPixel(j, i) == BLACK) {
xNum[i]++;
}
}
}
// 經過測試這樣得到的平均值最優 , 平均值的選取很重要
cNum = Arrays.copyOf(xNum, xNum.length);
Arrays.sort(cNum);
for (i = 31 * nWidth / 32; i < nWidth; i++) {
average += cNum[i];
}
average /= (nWidth / 28);
// 把需要切割的x點都存到cutY中,
List<Integer> cutX = new ArrayList<Integer>();
for (i = 0; i < nWidth; i += 2) {
if (xNum[i] >= average) {
cutX.add(i);
}
}
if (cutX.size() != 0) {
int temp = cutX.get(cutX.size() - 1);
// 因為線條有粗細,優化cutY
for (i = cutX.size() - 2; i >= 0; i--) {
int k = temp - cutX.get(i);
if (k <= 10) {
cutX.remove(i);
} else {
temp = cutX.get(i);
}
}
}
// 把切割的圖片都保存到YMat中
List<Mat> XMat = new ArrayList<Mat>();
for (i = 1; i < cutX.size(); i++) {
// 設置感興趣的區域
int startX = cutX.get(i - 1);
int width = cutX.get(i) - startX;
Mat temp = new Mat(mat, new Rect(startX, 0, width, nHeight));
Mat t = new Mat();
temp.copyTo(t);
XMat.add(t);
}
return XMat;
}
注:本文章參考了很多博客,感謝;主要是跟着一個博客來實現的https://blog.csdn.net/ysc6688/article/category/2913009(也是基於opencv來做的)感謝