1. 程式人生 > >基於Java及Opencv3.4.1的影象線條識別

基於Java及Opencv3.4.1的影象線條識別

  • 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;
	}
}