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


目录
相关文章
|
1天前
|
算法 计算机视觉
OpenCV(四十三):Shi-Tomas角点检测
OpenCV(四十三):Shi-Tomas角点检测
27 0
|
1天前
|
计算机视觉
OpenCV(三十八):二维码检测
OpenCV(三十八):二维码检测
65 0
|
1天前
|
编解码 计算机视觉
OpenCV(三十六):霍夫直线检测
OpenCV(三十六):霍夫直线检测
34 0
|
1天前
|
计算机视觉 索引
OpenCV(三十五):凸包检测
OpenCV(三十五):凸包检测
28 0
|
1天前
|
存储 资源调度 算法
Opencv(C++)系列学习---SIFT、SURF、ORB算子特征检测
Opencv(C++)系列学习---SIFT、SURF、ORB算子特征检测
|
1天前
|
存储 算法 计算机视觉
OpenCV(四十二):Harris角点检测
OpenCV(四十二):Harris角点检测
39 0
|
1天前
|
计算机视觉 Python Windows
OpenCV自动裁剪图片
OpenCV自动裁剪图片
10 1
|
1天前
|
机器学习/深度学习 传感器 算法
【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代
【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代
|
1天前
|
前端开发 API 计算机视觉
opencv绘制基本图形,在图片上添加文字
opencv绘制基本图形,在图片上添加文字
|
1天前
|
机器学习/深度学习 算法 自动驾驶
opencv python 图片叠加
【4月更文挑战第17天】