基於OpenCV的機器視覺應用&影象分割
阿新 • • 發佈:2018-12-20
對“ 待分割識別影象”資料夾中的 ” 所有 整版麻將圖片進行 分割 ,並輸出 識別 結果 :
原始碼:
#include <opencv2\core\core.hpp> #include <opencv2\highgui\highgui.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <iostream> using namespace cv; using namespace std; static int issame(Mat out, Mat std); int minvalue = INT_MAX; void HorizonProjection(const Mat& src, Mat& dst) //水平投影,const表示常量 { CV_Assert(src.depth() != sizeof(uchar)); dst.create(src.rows, 1, CV_32F); int i, j; const uchar* p; float* p_dst; for (i = 0; i < src.rows; i++) { p = src.ptr<uchar>(i); p_dst = dst.ptr<float>(i); p_dst[0] = 0; for (j = 0; j < src.cols; j++) { p_dst[0] += p[j]; } p_dst[0] = p_dst[0] / src.cols; } } void VerticalProjection(const Mat& src, Mat& dst) //垂直投影 { CV_Assert(src.depth() != sizeof(uchar)); dst.create(1, src.cols, CV_32F); int i, j; const uchar* p; float* p_dst = dst.ptr<float>(0); for (j = 0; j < src.cols; j++) { p_dst[j] = 0; for (i = 0; i < src.rows; i++) { p = src.ptr<uchar>(i); p_dst[j] += p[j]; } p_dst[j] = p_dst[j] / src.rows; } } int main() { Mat dstImage,gImage,sgImage,ogImage, srcImage = imread("a.jpg"); //有路徑要輸入 Mat hImage, vImage; int x1, x2, y1, y2; int x_proj_out, y_proj_out; int width_single, heigth_single; float *dst; float *t; int a[100],b[100],d[100]; int n=0,m=0,g=0; int w,h; int maxw=0,maxh=0; int numx=0, numy=0; //步驟一 cvtColor(srcImage, gImage, CV_BGR2GRAY); //顏色轉換函式 threshold(gImage, dstImage, 0, 255, THRESH_OTSU); //步驟二 HorizonProjection(dstImage, hImage); VerticalProjection(dstImage, vImage); for (int i = 0;;i++) { dst = hImage.ptr<float>(i); float t1 = dst[0], t2 = dst[1], t3 = dst[2], t4 = dst[3], t5 = dst[4]; if (t1!= 0 && t2 != 0 && t3!= 0 && t4 != 0 && t5 != 0) { y1 = i - 2; break; } } for (int i = hImage.rows;;i--) { dst = hImage.ptr<float>(i-5); float t1 = dst[0], t2 = dst[1], t3 = dst[2], t4 = dst[3], t5 = dst[4]; if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0) { y2 = i + 2; break; } } for (int i = 0;;i++) { dst = vImage.ptr<float>(0); float t1 = dst[i], t2 = dst[i+1], t3 = dst[i+2], t4 = dst[i+3], t5 = dst[i+4]; if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0) { x1 = i - 2; break; } } for (int i = vImage.cols;;i--) { dst = vImage.ptr<float>(0); float t1 = dst[i-4], t2 = dst[i-3], t3 = dst[i-2], t4 = dst[i-1], t5 = dst[i]; if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0) { x2 = i + 2; break; } } sgImage = gImage(Range(y1, y2), Range(x1, x2)); imshow("擷取的灰度圖", sgImage); // waitKey(0); //步驟三 threshold(sgImage, dstImage, 0, 255, THRESH_OTSU); imshow("二值影象", dstImage); Mat element = getStructuringElement(MORPH_ELLIPSE, Size(3, 3)); morphologyEx(dstImage, dstImage, CV_MOP_OPEN, element); imshow("形態學濾波", dstImage); waitKey(0); HorizonProjection(dstImage, hImage); VerticalProjection(dstImage, vImage); dst = hImage.ptr<float>(0);dst[0] = 255; dst = hImage.ptr<float>(1);dst[0] = 255; dst = hImage.ptr<float>(hImage.rows-1);dst[0] = 255; dst = hImage.ptr<float>(hImage.rows-2);dst[0] = 255; dst = vImage.ptr<float>(0);dst[0] = 255, dst[1] = 255, dst[vImage.cols - 1] = 255, dst[vImage.cols - 2] = 255; for (int i = 1;i < vImage.cols;i++) { dst = vImage.ptr<float>(0); if (dst[i] > 255 * 0.9) { dst[i] = 255; if (dst[i-1] == 0) { a[n] = i; n++; } } else { dst[i] = 0; if (dst[i-1] == 255) { a[n] = i; n++; } } } // imshow("111111111", vImage); for (int i = 0;i <= n-1;i += 1) { if ((a[i + 1] - a[i]) < 5) { for (int j = a[i];j <= a[i + 1];j++) { dst = vImage.ptr<float>(0); dst[j] = 255; } } } for (int i = 1;i < vImage.cols;i++) { dst = vImage.ptr<float>(0); if (dst[i]!=dst[i - 1] ) { b[m] = i; m++; } } // imshow("222222222", vImage); for (int i = 0;i <= m;i += 2) { if (maxw < b[i + 1] - b[i]) maxw = b[i + 1] - b[i];//maxw單個麻將最大寬度 } for (int i = 0;i <= m;i += 2) { w = b[i + 1] - b[i]; if (w > (maxw / 2)) { numx++; d[g] = b[i]; d[g+1] = b[i + 1]; g += 2; } } x_proj_out = (d[0] + d[g - 1]) / 2; n = 0, m = 0, g = 0; for (int i = 1;i < hImage.rows;i++) { t = hImage.ptr<float>(i - 1); dst = hImage.ptr<float>(i); if (dst[0] > 255 * 0.9) { dst[0] = 255; if (t[0] == 0) { a[n] = i; n++; } } else { dst[0] = 0; if (t[0] == 255) { a[n] = i; n++; } } } // imshow("111111", hImage); for (int i = 0;i <= n-1;i += 2) { if ((a[i + 1] - a[i]) < 10) { for (int j = a[i];j <= a[i + 1];j++) { dst = hImage.ptr<float>(j); dst[0] = 255; } } } // imshow("22222", hImage); for (int i = 1;i < hImage.rows;i++) { t = hImage.ptr<float>(i - 1); dst = hImage.ptr<float>(i); if (t[0] != dst[0]) { b[m] = i; m++; } } for (int i = 0;i <= m-2;i += 2) { h = b[i + 1] - b[i]; if (h < 0.95*maxw) { h = b[i + 3] - b[i]; if (h < 0.95*maxw) { h = b[i + 5] - b[i]; d[g] = b[i]; d[g + 1] = b[i + 5]; g += 2; i += 4; numy++; } else { d[g] = b[i]; d[g + 1] = b[i + 3]; g += 2; i += 2; numy++; } } else { d[g] = b[i]; d[g + 1] = b[i + 1]; g += 2; numy++; } } for (int i = 0;i <= g;i += 2) { if (maxh < d[i + 1] - d[i]) maxh = d[i + 1] - d[i]; } y_proj_out = (d[0] + d[g - 1]) / 2; heigth_single =(sgImage.rows-10) / numy; width_single =(sgImage.cols-10) / numx; int num = numx*numy; Mat *singleImage = new Mat[num]; int xb, yb; int xb1,yb1,xe, ye; int count=0; xb = x_proj_out - (width_single*((float)numx / 2)); printf("%d %d", xb,x_proj_out); yb = y_proj_out - (heigth_single*((float)numy / 2)); for (int i=0;i < numy;i++) { for (int j = 0;j < numx;j++) { xb1 = xb + width_single*(j); xe = xb + width_single*(j + 1); yb1 = yb + heigth_single*(i); ye = yb + heigth_single*(i + 1); singleImage[count] = sgImage(Range(yb1,ye), Range(xb1,xe)); count++; } } char filename[30]; char filename2[30]; char filename3[30]; char filename4[30]; char filename5[30]; char filename6[30]; char filename7[30]; Mat *dsImage=new Mat[num], *outImage=new Mat[num]; Mat stdImage[34], grayImage[34], threImage[34], tempImage[34]; //步驟4 //分割出來的單個麻將灰度圖片 for (int i = 0; i <num; i++) { sprintf_s(filename, "%d.jpg", i + 1); imshow(filename, singleImage[i]); } //縮放尺寸 for (int i = 0; i <num; i++) { resize(singleImage[i], dsImage[i], Size(32, 48), INTER_LINEAR); sprintf_s(filename2, "change(%d).jpg", i + 1); //imwrite(filename2, dstImage[i]); //imshow(filename2,dstImage[i]); } //閾值化 for (int i = 0; i <num; i++) { threshold(dsImage[i], outImage[i], 0, 255, THRESH_OTSU); sprintf_s(filename3, "threshold(%d).jpg", i + 1); //imshow(filename3, outImage[i]); for (int m = 0; m < outImage[i].cols; m++) { outImage[i].ptr<uchar>(0)[m] = 255; } for (int m = 0; m < outImage[i].cols; m++) { outImage[i].ptr<uchar>(47)[m] = 255; } for (int m = 0; m < outImage[i].rows; m++) { outImage[i].ptr<uchar>(m)[0] = 255; } for (int m = 0; m < outImage[i].rows; m++) { outImage[i].ptr<uchar>(m)[31] = 255; } sprintf_s(filename4, "thresholdchange(%d).jpg", i + 1); //imshow(filename4, outImage[i]); } //步驟5 //閾值化模板麻將 for (int i = 0; i <34; i++) { sprintf_s(filename5, "%d.jpg", i + 1); stdImage[i] = imread(filename5); //imshow(filename5,stdImage[i]); } for (int i = 0; i <34; i++) { cvtColor(stdImage[i], grayImage[i], CV_RGB2GRAY); threshold(grayImage[i], threImage[i], 0, 255, THRESH_OTSU); for (int m = 0; m < threImage[i].cols; m++) { threImage[i].ptr<uchar>(0)[m] = 255; } for (int m = 0; m < threImage[i].cols; m++) { threImage[i].ptr<uchar>(47)[m] = 255; } for (int m = 0; m < threImage[i].rows; m++) { threImage[i].ptr<uchar>(m)[0] = 255; } for (int m = 0; m < threImage[i].rows; m++) { threImage[i].ptr<uchar>(m)[31] = 255; } sprintf_s(filename6, "thresholdstandard(%d).jpg", i + 1); //imshow(filename6, threImage[i]); } //擴大成模板麻將 for (int i = 0; i <34; i++) { copyMakeBorder(threImage[i], tempImage[i], 9, 9, 6, 6, BORDER_REPLICATE); sprintf_s(filename7, "temp(%d).jpg", i + 1); // imshow(filename7, tempImage[i]); } //步驟6 待識別outImage[i] 模板tempImage[i] int nvalue; int minv = INT_MAX; int n1; for (int j = 0; j < num; j++) { for (int i = 0; i < 34; i++) { nvalue = issame(outImage[j], tempImage[i]); if (nvalue < minv) { minv = nvalue; n1 = i; } } printf("(%d).jpg = %d.jpg \n", j + 1, n1 + 1); minv = INT_MAX; } waitKey(0); return 0; } static int issame(Mat out, Mat std) { Mat temp; int value = INT_MAX; int res = 0; int x, y; for (int x1 = 0; x1 < 13; x1++) { for (int y1 = 0; y1 < 19; y1++) { temp = std(Range(y1, y1 + 47), Range(x1, x1 + 31)); for (int j = 0; j < 47; j++) { for (int i = 0; i < 31; i++) { res = res + abs(out.at<uchar>(j, i) - temp.at<uchar>(j, i)); } } if (res < minvalue) { minvalue = res; } if (minvalue < value) { value = minvalue; } res = 0; minvalue = INT_MAX; } } return value; }
處理的結果:
關閉擷取的灰度圖、二值影象、形態學濾波視窗後:
程式執行後出現的結果:
即為分割識別後的結果。