Opencv:10个步骤检测出图片中条形码

简介: 1. 原图像大小调整,提高运算效率2. 转化为灰度图3. 高斯平滑滤波4.求得水平和垂直方向灰度图像的梯度差,使用Sobel算子5.

1. 原图像大小调整,提高运算效率



2. 转化为灰度图



3. 高斯平滑滤波



4.求得水平和垂直方向灰度图像的梯度差,使用Sobel算子



5.均值滤波,消除高频噪声



6.二值化



7.闭运算,填充条形码间隙



8. 腐蚀,去除孤立的点



9. 膨胀,填充条形码间空隙,根据核的大小,有可能需要2~3次膨胀操作



10.通过findContours找到条形码区域的矩形边界



实现:

[cpp]  view plain  copy
  1. #include "core/core.hpp"  
  2. #include "highgui/highgui.hpp"  
  3. #include "imgproc/imgproc.hpp"  
  4.   
  5. using namespace cv;  
  6.   
  7. int main(int argc,char *argv[])  
  8. {  
  9.     Mat image,imageGray,imageGuussian;  
  10.     Mat imageSobelX,imageSobelY,imageSobelOut;  
  11.     image=imread(argv[1]);  
  12.   
  13.     //1. 原图像大小调整,提高运算效率  
  14.     resize(image,image,Size(500,300));  
  15.     imshow("1.原图像",image);  
  16.   
  17.     //2. 转化为灰度图  
  18.     cvtColor(image,imageGray,CV_RGB2GRAY);  
  19.     imshow("2.灰度图",imageGray);  
  20.   
  21.     //3. 高斯平滑滤波  
  22.     GaussianBlur(imageGray,imageGuussian,Size(3,3),0);  
  23.     imshow("3.高斯平衡滤波",imageGuussian);  
  24.   
  25.     //4.求得水平和垂直方向灰度图像的梯度差,使用Sobel算子  
  26.     Mat imageX16S,imageY16S;  
  27.     Sobel(imageGuussian,imageX16S,CV_16S,1,0,3,1,0,4);  
  28.     Sobel(imageGuussian,imageY16S,CV_16S,0,1,3,1,0,4);  
  29.     convertScaleAbs(imageX16S,imageSobelX,1,0);  
  30.     convertScaleAbs(imageY16S,imageSobelY,1,0);  
  31.     imageSobelOut=imageSobelX-imageSobelY;  
  32.     imshow("4.X方向梯度",imageSobelX);  
  33.     imshow("4.Y方向梯度",imageSobelY);  
  34.     imshow("4.XY方向梯度差",imageSobelOut);    
  35.   
  36.     //5.均值滤波,消除高频噪声  
  37.     blur(imageSobelOut,imageSobelOut,Size(3,3));  
  38.     imshow("5.均值滤波",imageSobelOut);   
  39.   
  40.     //6.二值化  
  41.     Mat imageSobleOutThreshold;  
  42.     threshold(imageSobelOut,imageSobleOutThreshold,180,255,CV_THRESH_BINARY);     
  43.     imshow("6.二值化",imageSobleOutThreshold);  
  44.   
  45.     //7.闭运算,填充条形码间隙  
  46.     Mat  element=getStructuringElement(0,Size(7,7));  
  47.     morphologyEx(imageSobleOutThreshold,imageSobleOutThreshold,MORPH_CLOSE,element);      
  48.     imshow("7.闭运算",imageSobleOutThreshold);  
  49.   
  50.     //8. 腐蚀,去除孤立的点  
  51.     erode(imageSobleOutThreshold,imageSobleOutThreshold,element);  
  52.     imshow("8.腐蚀",imageSobleOutThreshold);  
  53.   
  54.     //9. 膨胀,填充条形码间空隙,根据核的大小,有可能需要2~3次膨胀操作  
  55.     dilate(imageSobleOutThreshold,imageSobleOutThreshold,element);  
  56.     dilate(imageSobleOutThreshold,imageSobleOutThreshold,element);  
  57.     dilate(imageSobleOutThreshold,imageSobleOutThreshold,element);  
  58.     imshow("9.膨胀",imageSobleOutThreshold);        
  59.     vector<vector<Point>> contours;  
  60.     vector<Vec4i> hiera;  
  61.   
  62.     //10.通过findContours找到条形码区域的矩形边界  
  63.     findContours(imageSobleOutThreshold,contours,hiera,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);  
  64.     for(int i=0;i<contours.size();i++)  
  65.     {  
  66.         Rect rect=boundingRect((Mat)contours[i]);  
  67.         rectangle(image,rect,Scalar(255),2);      
  68.     }     
  69.     imshow("10.找出二维码矩形区域",image);  
  70.   
  71.     waitKey();  
  72. }  

使用另一幅图片的效果如下:



底部的二维码左侧边界定位错位,检测发现在二值化的时候左侧第二个条码部分被归零了,导致在之后的腐蚀操作中被腐蚀掉了。调整阈值分界值180到160,重新运行正确:



安卓:


  * 提取区域
    * */
    public Bitmap getImageDiscriminatePoint() {
        Mat imageSobelX = new Mat();
        Mat imageSobelY = new Mat();
        Mat imageSobelOut = new Mat();

        Mat image = new Mat();
        Mat imageGray = new Mat();
        Mat imageGuussian = new Mat();

        Utils.bitmapToMat(source, image);

        //1:调整图片大小
        Imgproc.resize(image, image, new Size(image.rows() / 4, image.cols() / 4));

        //2:灰度化
        Imgproc.cvtColor(image, imageGray, Imgproc.COLOR_BGR2GRAY);

        //3:高斯平滑, Imgproc.getGaussianKernel();高斯滤波
        Imgproc.GaussianBlur(imageGray, imageGuussian, new Size(3,3), 0);

        //4:求得水平和垂直方向灰度图像的梯度差,使用Sobel算子
        Mat imageX16S = new Mat();
        Mat imageY16S = new Mat();
        Imgproc.Sobel(imageGuussian, imageX16S, CvType.CV_16S, 1, 0, 3, 1, 0, 4);
        Imgproc.Sobel(imageGuussian, imageY16S, CvType.CV_16S, 0, 1, 3, 1, 0, 4);


        Core.convertScaleAbs(imageX16S, imageSobelX, 1, 0);
        Core.convertScaleAbs(imageY16S, imageSobelY, 1, 0);
       // imageSobelOut = imageSobelX - imageSobelY;

        Core.addWeighted(imageSobelX, 0.5, imageSobelY, 0.5, 1, imageSobelOut);//计算梯度和
        //Core.divide(imageSobelX, imageSobelY, imageSobelOut);



        //5:均值滤波,消除高频噪声
        Imgproc.blur(imageSobelOut, imageSobelOut, new Size(3, 3));



        //6:二值化
//        Mat imageSobleOutThreshold = new Mat();
//        Imgproc.threshold(imageSobelOut, imageSobleOutThreshold, 100, 255, Imgproc.THRESH_BINARY);

        //7.闭运算,填充条形码间隙
//        Mat  element = Imgproc.getStructuringElement(0, new Size(7, 7));
//        Imgproc.morphologyEx(imageSobleOutThreshold, imageSobleOutThreshold, Imgproc.MORPH_CLOSE, element);


//        //8. 腐蚀,去除孤立的点
//       // Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8));
//        Imgproc.erode(imageSobleOutThreshold, imageSobleOutThreshold, element);
//
//        //9. 膨胀,填充条形码间空隙,根据核的大小,有可能需要2~3次膨胀操作
//        Imgproc.dilate(imageSobleOutThreshold,imageSobleOutThreshold,element);

        image = imageSobelOut;

        //10.通过findContours找到条形码区域的矩形边界
//        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
//        Mat hierarcy = new Mat();
//        Imgproc.findContours(imageSobleOutThreshold, contours, hierarcy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
//
//        Log.d("-----------------", "求灰度图"+contours.size());
//        for(int i=0;i<contours.size();i++) {
         //   Rect rect = Imgproc.boundingRect(contours.get(i));
//            Log.d("-----------------", "这里知心了"+rect.x+"------"+rect.y+"-----"+rect.width+"-------"+rect.height);
//            Imgproc.rectangle(image, new Point(rect.x + rect.width, rect.y + rect.height),new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(177));
//        }



        idcardBit = Bitmap.createBitmap(image.cols(), image.rows(), Bitmap.Config.RGB_565);//ARGB_8888,RGB_565
        Utils.matToBitmap(image, idcardBit);

        //腐蚀
//        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8));
//        Imgproc.erode(idcardMat, idcardMat, kernel);

//        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(50, 50));
//        Imgproc.erode(idcardMat, idcardMat, kernel);


          hanler.sendMessage(new Message());

//        File file = new File(Environment.getExternalStorageDirectory()+"/AiLingGong/", "test.jpg");
//        try {
//            FileOutputStream out = new FileOutputStream(file);
//            idcardBit.compress(Bitmap.CompressFormat.JPEG, 100, out);
//            out.flush();
//            out.close();
//        } catch (FileNotFoundException e) {
//            Log.d("-----------------", "111111");
//            e.printStackTrace();
//        } catch (IOException e) {
//            Log.d("----------------", "2222222");
//            e.printStackTrace();
//        }



//        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
//        Mat hierarcy = new Mat();
//        Imgproc.findContours(idcardMat, contours, hierarcy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
//
//        int idCardNumberY = 0;
//
//        for(int i=0;i<contours.size();i++){
//            Rect rect = Imgproc.boundingRect(contours.get(i));
//            Imgproc.rectangle(idcardMat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0), 3);
//            if(rect.width > 500 && rect.width/rect.height >= 6){
//                //这里可能取到多个轮廓噢,“地址的轮廓也可能会进来”,需要简单筛选一下下面的轮廓,(之前bug原因,腐蚀不够高,大量轮廓进来了)
//                if (idCardNumberY < rect.y) {
//                    idCardNumberY = rect.y;
//                    idcardBit = cropDownPart(source, rect.x, rect.y, rect.width, rect.height);
//                }
//
//                File file = new File(Environment.getExternalStorageDirectory()+"/AiLingGong/", "w"+rect.width+"h"+rect.height+".jpg");
//                try {
//                    FileOutputStream out = new FileOutputStream(file);
//                    idcardBit.compress(Bitmap.CompressFormat.JPEG, 100, out);
//                    out.flush();
//                    out.close();
//                } catch (FileNotFoundException e) {
//                    e.printStackTrace();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
        return idcardBit;
    }


目录
相关文章
|
2月前
|
计算机视觉
Opencv学习笔记(十二):图片腐蚀和膨胀操作
这篇文章介绍了图像腐蚀和膨胀的原理、作用以及使用OpenCV实现这些操作的代码示例,并深入解析了开运算和闭运算的概念及其在图像形态学处理中的应用。
139 1
Opencv学习笔记(十二):图片腐蚀和膨胀操作
|
2月前
|
计算机视觉 Python
Opencv学习笔记(二):如何将整个文件下的彩色图片全部转换为灰度图
使用OpenCV库将一个文件夹内的所有彩色图片批量转换为灰度图,并提供了相应的Python代码示例。
38 0
Opencv学习笔记(二):如何将整个文件下的彩色图片全部转换为灰度图
|
2月前
|
计算机视觉 Python
Opencv学习笔记(一):如何将得到的图片保存在指定目录以及如何将文件夹里所有图片以数组形式输出
这篇博客介绍了如何使用OpenCV库在Python中将图片保存到指定目录,以及如何将文件夹中的所有图片读取并以数组形式输出。
169 0
Opencv学习笔记(一):如何将得到的图片保存在指定目录以及如何将文件夹里所有图片以数组形式输出
|
2月前
|
计算机视觉
Opencv学习笔记(八):如何通过cv2读取视频和摄像头来进行人脸检测(jetson nano)
如何使用OpenCV库通过cv2模块读取视频和摄像头进行人脸检测,并提供了相应的代码示例。
105 1
|
2月前
|
计算机视觉
Opencv错误笔记(一):通过cv2保存图片采用中文命名出现乱码
在使用OpenCV的cv2模块保存带有中文命名的图片时,直接使用cv2.imwrite()会导致乱码问题,可以通过改用cv2.imencode()方法来解决。
168 0
Opencv错误笔记(一):通过cv2保存图片采用中文命名出现乱码
|
4月前
|
计算机视觉 Windows Python
windows下使用python + opencv读取含有中文路径的图片 和 把图片数据保存到含有中文的路径下
在Windows系统中,直接使用`cv2.imread()`和`cv2.imwrite()`处理含中文路径的图像文件时会遇到问题。读取时会返回空数据,保存时则无法正确保存至目标目录。为解决这些问题,可以使用`cv2.imdecode()`结合`np.fromfile()`来读取图像,并使用`cv2.imencode()`结合`tofile()`方法来保存图像至含中文的路径。这种方法有效避免了路径编码问题,确保图像处理流程顺畅进行。
390 1
|
2月前
|
机器学习/深度学习 计算机视觉
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
本文介绍了如何使用OpenCV进行特定区域的目标检测,包括人脸检测实例,展示了两种实现方法和相应的代码。
73 1
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
|
2月前
|
Serverless 计算机视觉
语义分割笔记(三):通过opencv对mask图片来画分割对象的外接椭圆
这篇文章介绍了如何使用OpenCV库通过mask图像绘制分割对象的外接椭圆。首先,需要加载mask图像,然后使用`cv2.findContours()`寻找轮廓,接着用`cv2.fitEllipse()`拟合外接椭圆,最后用`cv2.ellipse()`绘制椭圆。文章提供了详细的代码示例,展示了从读取图像到显示结果的完整过程。
62 0
语义分割笔记(三):通过opencv对mask图片来画分割对象的外接椭圆
|
2月前
|
算法 计算机视觉 Python
圆形检测算法-基于颜色和形状(opencv)
该代码实现了一个圆检测算法,用于识别视频中的红色、白色和蓝色圆形。通过将图像从RGB转换为HSV颜色空间,并设置对应颜色的阈值范围,提取出目标颜色的区域。接着对这些区域进行轮廓提取和面积筛选,使用霍夫圆变换检测圆形,并在原图上绘制检测结果。
88 0
|
4月前
|
存储 编解码 API
python多种方法压缩图片,opencv、PIL、tinypng、pngquant压缩图片
python多种方法压缩图片,opencv、PIL、tinypng、pngquant压缩图片
307 1