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