基于Java及Opencv3.4.1的图像线条识别

  • 1.基于Java的图像识别,可以使用OpenCV函数包,本人用了OpenCV3.4.1,配置过程网上很齐全,也比较简单,在此不再赘述。我要识别的线条较粗,所识别的线条是图像中间二维码两侧的横线。因为白条很亮,最先开始我想先对图像制定区域进行二值化处理,再对指定区域进行像素点统计,但该方法准确度不高。最后采用canny+二值化+Hough transform+扫描识别的方案。

基于Java及Opencv3.4.1的图像线条识别_第1张图片

  • 2 .为了位二维码的一些边缘特性区分开,以及其他反光因素的影响尽可能降低。所以先采取opencv的blur函数进行图像模糊。然后用canny边缘识别函数提取图像的边缘特性,此刻的图像还是包涵了很多其他干扰,采取了二值化,以便识别过程进行特征区分。但是所提取的边缘信息还是很多,并且不好识别线条位置。       
  • 3.增强较大的轮廓边缘特征,可采用概率霍夫变换或者标准霍夫变换。两种霍夫变换在源代码中都有,我最后采用的是标准霍夫变换,这样识别的线条较为平整。之后就可以进行图像扫描识别。当然我所识别的图像需要对齐,不能有太大的左右角度位移。这也可以增加一个角度旋转的模块,先平齐,而后再识别。

基于Java及Opencv3.4.1的图像线条识别_第2张图片

源代码如下

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);y200) 
					{	
						count2++;
					}
				else
					{
					if(Max_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_y2&&count3<5)
		{
			int Max_del_y=y_location[1]-y_location[0];
			int Min_del_y=Max_del_y;
			for(int i=1;iMax_del_y) Max_del_y=p;
				else
					if(pget_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;
	}
}

你可能感兴趣的:(基于Java及Opencv3.4.1的图像线条识别)