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

来源:互联网 发布:淘宝生产许可证编号qs 编辑:程序博客网 时间:2024/04/29 10:11

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


原创粉丝点击