基於Java及Opencv3.4.1的影象線條識別
阿新 • • 發佈:2019-01-11
- 1.基於Java的影象識別,可以使用OpenCV函式包,本人用了OpenCV3.4.1,配置過程網上很齊全,也比較簡單,在此不再贅述。我要識別的線條較粗,所識別的線條是影象中間二維碼兩側的橫線。因為白條很亮,最先開始我想先對影象制定區域進行二值化處理,再對指定區域進行畫素點統計,但該方法準確度不高。最後採用canny+二值化+Hough transform+掃描識別的方案。
- 2 .為了位二維碼的一些邊緣特性區分開,以及其他反光因素的影響儘可能降低。所以先採取opencv的blur函式進行影象模糊。然後用canny邊緣識別函式提取影象的邊緣特性,此刻的影象還是包涵了很多其他干擾,採取了二值化,以便識別過程進行特徵區分。但是所提取的邊緣資訊還是很多,並且不好識別線條位置。
- 3.增強較大的輪廓邊緣特徵,可採用概率霍夫變換或者標準霍夫變換。兩種霍夫變換在原始碼中都有,我最後採用的是標準霍夫變換,這樣識別的線條較為平整。之後就可以進行影象掃描識別。當然我所識別的影象需要對齊,不能有太大的左右角度位移。這也可以增加一個角度旋轉的模組,先平齊,而後再識別。
原始碼如下
import org.opencv.core.*; import org.opencv.core.Point; //import org.opencv.highgui.*; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.*; public class Img_confirm { public static void main(String[] args) { // TODO Auto-generated method stub System.loadLibrary(Core.NATIVE_LIBRARY_NAME); Mat image = Imgcodecs.imread("F:\\18\\eclipse-workspace\\img\\0038.jpg"); int []y_location=new int[10]; try { Imgproc.blur(image,image,new Size(4,4));//影象模糊 Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2GRAY);//灰度處理 Mat binaryMat = new Mat(image.height(),image.width(),CvType.CV_8UC1); // Imgproc.blur(binaryMat,binaryMat,new Size(3,3)); /* double lowThresh =50;//雙閥值抑制中的低閥值 double heightThresh = 200;//雙閥值抑制中的高閥值 Mat lineMat = new Mat(); Imgproc.Canny(image,image,40,200.0); // Imgproc.Canny(image, image,lowThresh, heightThresh,3,true); Imgproc.HoughLinesP(image, lineMat, 1, Math.PI/180, 70, 30, 3); Imgproc.threshold(image, binaryMat, 190, 255, Imgproc.THRESH_BINARY);//二值化閾值設定 //Imgproc.Canny(binaryMat,binaryMat,30.0,200.0); // Imgproc.adaptiveThreshold(image, image, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 25, 30); int[] a = new int[(int)lineMat.total()*lineMat.channels()]; //陣列a儲存檢測出的直線端點座標 lineMat.get(0,0,a); for (int i = 0; i < a.length; i += 4) { Imgproc.line(binaryMat, new Point(a[i], a[i+1]), new Point(a[i+2], a[i+3]), new Scalar(255, 0, 255),8); } *概率霍夫變換 */ // Imgproc.Canny(srcImage, dstImage, 400, 500, 5, false); Imgproc.Canny(image,image,100,250.0);//canny邊緣檢測 Imgproc.threshold(image, binaryMat, 190, 255, Imgproc.THRESH_BINARY);//二值化閾值設定 //標準霍夫變換 Mat storage = new Mat(); Imgproc.HoughLines(image, storage, 1, Math.PI / 180, 100, 0, 0,0,10); for (int x = 0; x < storage.rows(); x++) { double[] vec = storage.get(x, 0); double rho = vec[0]; double theta = vec[1]; Point pt1 = new Point(); Point pt2 = new Point(); double a = Math.cos(theta); double b = Math.sin(theta); double x0 = a * rho; double y0 = b * rho; pt1.x = Math.round(x0 + 1000 * (-b)); pt1.y = Math.round(y0 + 1000 * (a)); pt2.x = Math.round(x0 - 1000 * (-b)); pt2.y = Math.round(y0 - 1000 * (a)); if (theta >= 0) { Imgproc.line(binaryMat, pt1, pt2, new Scalar(255, 255, 255),5); } } int Width=binaryMat.width(); int Height=binaryMat.height(); System.out.println(Width+" "+Height); /* int Width1=get_num(Width,0.25);//Width第一個位置點 int Width2=get_num(Width,0.75);//Width第二個位置點 int Height1=get_num(Height,0.16708);//Height第一個位置點 int Height2=get_num(Height,0.70);//Height第二個位置點 int Height_Plus=get_num(Height,0.1538);//檢測寬度設定 System.out.println(Height_Plus); if(detection(binaryMat,Height1,Height_Plus,Width1,Width2)&&detection(binaryMat,Height2,Height_Plus,Width1,Width2)) System.out.println("符合要求"); else System.out.println("不符合要求"); 第一種普通演算法設定 */ int location_num=Detection_location(image,binaryMat,Height,Width,y_location); System.out.println("直線條數:"+location_num); if(Decision(location_num,y_location,Height)) System.out.println("符合要求"); else System.out.println("不符合要求"); // binaryMat.imshow(); Imgcodecs.imwrite("F:\\18\\eclipse-workspace\\result.jpg", binaryMat); Imgcodecs.imwrite("F:\\18\\eclipse-workspace\\result1.jpg", image); }catch(Exception e) { System.out.println("讀取錯誤"); } } //計運算元函式 public static int get_num(int h,double c) { double fl = (float)h; fl=fl*c; int result=(int)fl; return result; } //檢測白條位置子函式 public static int Detection_location(Mat image,Mat binaryMat,int Height,int Width,int y_location[]) { int count3=0; int Y_confirm=0; int Max_count2=0; for(int y=get_num(Height,0.15);y<get_num(Height,0.85);y++) { int count2=0; for(int x=get_num(Width,0.15);x<get_num(Width,0.85);x++) { int data=(int)binaryMat.get(y, x)[0]; if(data>200) { count2++; } else { if(Max_count2<count2) Max_count2=count2; count2=0; } if(count2>=get_num(Width,0.4)) Max_count2=count2; } count2=0; if(Max_count2 >= get_num(Width,0.4)) { int del_y; del_y=y-Y_confirm; if(del_y>get_num(Height,0.15)) { y_location[count3]=y; count3++; Y_confirm=y; System.out.println("點數"+Max_count2+"Height"+y); Imgproc.line(image,new Point(0,y),new Point(Width,y),new Scalar(255,0,255)); } } Max_count2=0; } return count3; } //決策子函式 public static boolean Decision(int count3,int y_location[],int Height) { boolean flag=false; if(count3==2) { int del_y=y_location[1]-y_location[0]; if(del_y>get_num(Height,0.35)&&del_y<get_num(Height,0.8)) flag=true; else flag=false; } else if(count3>2&&count3<5) { int Max_del_y=y_location[1]-y_location[0]; int Min_del_y=Max_del_y; for(int i=1;i<count3-1;i++) { int p=y_location[i+1]-y_location[i]; if(p>Max_del_y) Max_del_y=p; else if(p<Min_del_y)Min_del_y=p; // System.out.println("最大:"+Max_del_y+"最小:"+Min_del_y); } if(Max_del_y>get_num(Min_del_y,1.7)&&Max_del_y<=get_num(Min_del_y,2.7)) flag=true; System.out.println("最大:"+Max_del_y+"最小:"+Min_del_y); } else flag=false; return flag; } //二值化方法判定子函式(可刪) public static boolean detection(Mat binaryMat,int Height,int Height_P,int Width1,int Width2) { int count1 = 0; int Height2=Height+Height_P; for (int y = Height; y < Height2; y++) { for (int x = Width1; x < Width2; x++) { double[] data =binaryMat.get(y, x); if (data[0] >= 200) count1 = count1 + 1; } } System.out.println(count1); if(count1>1000) return true; else return false; } }