小目标二维码检测

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件        :main.py 
@说明        :小目标二维码检测方法
@时间        :2020/01/07 08:31:52
@作者        :钱彬
@版本        :1.0
'''

import numpy as np
import cv2

if __name__ == "__main__":
    #读取图像
    filepath = "80.jpg" 
    img = cv2.imread(filepath) 
    imgHeight,imgWidth,channel = np.shape(img)
    # 转灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换灰色

    # 计算梯度
    ddepth = cv2.CV_32F

    gradX = cv2.Sobel(gray, ddepth=ddepth, dx=1, dy=0, ksize=-10)
    gradY = cv2.Sobel(gray, ddepth=ddepth, dx=0, dy=1, ksize=-10)

    gradient = cv2.subtract(gradX, gradY)
    gradient = cv2.convertScaleAbs(gradient)

    # 模糊和二值化
    blurred = cv2.blur(gradient, (5,5))
    (_, thresh) = cv2.threshold(blurred, 185, 255, cv2.THRESH_BINARY)

    # 形态学处理
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

    #膨胀和腐蚀操作
    closed = cv2.erode(closed, None, iterations=5)
    closed = cv2.dilate(closed, None, iterations=5)

    #查找连通域
    cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    #绘制轮廓
    #cv2.drawContours(img,cnts[1],-1,(0,0,255),1,lineType=cv2.LINE_AA)  #绘制实际轮廓

    for i in range(0,len(cnts[1])):
        rect = cv2.minAreaRect(cnts[1][i]) # 得到最小外接矩形(中心(x,y), (宽,高), 旋转角度)
        w,h=rect[1]
        if w/h>4 or h/w>4 or h>imgWidth/5 or w>imgWidth/5: #去除长宽比超过4倍的矩形框
            continue
        
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        # 画出来
        cv2.drawContours(img, [box], 0, (255, 0, 0), 1)

    cv2.imshow("Temp Image",img) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows()

#include <iostream>
#include <string>
#include <opencv4/opencv2/opencv.hpp>
#include <opencv4/opencv2/core.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/objdetect.hpp>
#include <opencv4/opencv2/imgproc/types_c.h>
#include <opencv4/opencv2/videoio.hpp>
#include <opencv4/opencv2/imgcodecs.hpp>

#include <zbar.h>  //导入zbar库
#include <time.h>

using namespace std;
using namespace cv;
using namespace zbar;

//定义计算时间的函数
unsigned long GetTickCount()
{
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

//定义一个结构体用于存储每个码
typedef struct
{
  string type;
  string data;
  vector <Point> location;
} decodedObject;

// 对图像进行码检测
void decode(Mat &im, vector<decodedObject>&decodedObjects)
{
  // 创建zbar扫码器
  ImageScanner scanner;

  // 配置扫码器参数
  scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);//ZBAR_NONE表示针对所有码进行检测(ZBAR_QRCODE表示只检测二维码)

  // 将图像转换为灰度图
  Mat imGray;
  if(im.channels()==1)
  {
      imGray=im.clone();
  }
  else
  {
    cvtColor(im, imGray,COLOR_BGR2GRAY);
  }

  // 将图像转换为zbar图像格式,即Y800格式
  Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);

  // 开始扫码
  int n = scanner.scan(image);

  // 输出扫码结果
  for(Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
  {
    decodedObject obj;

    obj.type = symbol->get_type_name();//码类型
    obj.data = symbol->get_data();//码解析字符串

    // 输出结果至控制台
    cout << "类型 : " << obj.type;
    cout << "   解码内容 : " << obj.data << endl;

    // 获取码的定位坐标
    for(int i = 0; i< symbol->get_location_size(); i++)
    {
      obj.location.push_back(Point(symbol->get_location_x(i),symbol->get_location_y(i)));
    }

    //每个检测结果存储于decodedObjects变量
    decodedObjects.push_back(obj);
  }
}

// 展示码
void display(Mat &im, vector<decodedObject>&decodedObjects)
{
  // 循环每一个码
  for(int i = 0; i < decodedObjects.size(); i++)
  {
    vector<Point> points = decodedObjects[i].location;
    vector<Point> hull;//多边形

    // 如果超过4个点,则采用多边形进行外接框绘制
    if(points.size() > 4)
      convexHull(points, hull);
    else
      hull = points;

    // 获取多边形点的个数
    int n = hull.size();

    for(int j = 0; j < n; j++)
    {
      line(im, hull[j], hull[ (j+1) % n], Scalar(255,0,0), 3);
    }

  }
}

int main( int argc, char** argv )
{
    //打开摄像头
    VideoCapture cap(1);

    //创建显示窗口
    namedWindow("USB Camera", WINDOW_AUTOSIZE);

    //逐帧显示
    while(true)
    {        
        Mat img;

        if (!cap.read(img))
        {
            std::cout<<"捕获失败"<<std::endl;
            break;
        }
        int start = GetTickCount();

        Mat img1 = img.clone();

        int new_width,new_height,width,height,channel;
        width=img.cols;
        height=img.rows;
        channel=img.channels();
        //cout<<width<<"  "<<height<<"  "<<channel<<endl;

//        Mat img1(Size(width, height), img.depth());
//        img.copyTo(img1);

        //调整图像大小
        new_width=800;
        if(width>new_width)
        {
            new_height=int(new_width*1.0/width*height);
        }
        resize(img, img, cv::Size(new_width, new_height), INTER_LINEAR);

        //图像灰度化
        Mat gray;
        cvtColor(img, gray,COLOR_BGR2GRAY);

        //计算梯度
        Mat xgrad, ygrad,gradient;

        Sobel(gray,xgrad, CV_16S, 1, 0, -10,1);
        Sobel(gray,ygrad, CV_16S, 0, 1, -10,1);

        subtract(xgrad, ygrad,gradient);
        convertScaleAbs(gradient,gradient);

        // 模糊和二值化
        blur(gradient,gradient,Size(5,5));
        threshold(gradient,gradient, 210, 255, THRESH_BINARY);

//        uchar* pxVec=gray.ptr<uchar>(0);
//        //遍历访问Mat中各个像素值
//        int i, j;
//        int px;
//        for (i = 0; i < gray.rows; i++)
//        {
//            uchar* pgray = gray.ptr<uchar>(i);
//            uchar* pgradient = gradient.ptr<uchar>(i);
//            for (j = 0; j < gray.cols; j++)
//            {
//                if(pgray[j]>200)
//                pgradient[j]=0;
//                //do anything

//            }
//        }

        // 形态学处理
        Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
        morphologyEx(gradient,gradient, MORPH_CLOSE, kernel);

        // 膨胀和腐蚀操作
        erode(gradient,gradient, Mat(),Point(-1,-1), 3);
        dilate(gradient,gradient, Mat(), Point(-1,-1),3);

        // 寻找连通域
        vector<vector<Point>> contours;
        vector<Vec4i> hierarcy;
        findContours(gradient, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

        // 查找最小外接矩形
        vector<Rect> boundRect(contours.size());  //定义外接矩形集合
        vector<RotatedRect> box(contours.size()); //定义最小外接矩形集合
        Point2f rect[4];
        for(int i=0; i<contours.size(); i++)
        {
            box[i] = minAreaRect(Mat(contours[i]));
            boundRect[i] = boundingRect(Mat(contours[i]));
            int w=box[i].size.width;
            int h=box[i].size.height;
            float angle=box[i].angle;
            //添加限制条件
            if(w>new_width/5 || h>new_width/5 || w<10 || h<10) //去除太大或太小的矩形框
                continue;
            if((angle>30 && angle<60)||(angle>120 && angle<150)||(angle>210 && angle<240)||(angle>300 && angle<330))
                continue;

            //利用高清图进行zbar检测
            Rect rect1;
            rect1.x=int((width*1.0/new_width)*boundRect[i].x);
            rect1.y=int((height*1.0/new_height)*boundRect[i].y);
            rect1.width=int((width*1.0/new_width)*boundRect[i].width);
            rect1.height=int((height*1.0/new_height)*boundRect[i].height);
            //cout<<rect1.x<<" "<<rect1.y<<" "<<rect1.width<<" "<<rect1.height<<endl;
            Mat cropImg = img1(rect1);

            vector<decodedObject> decodedObjects;

            decode(cropImg, decodedObjects);

            //display(img, decodedObjects);
            if(decodedObjects.size()==0)
            {
                decodedObjects.clear();
                continue;
            }
            else
                decodedObjects.clear();

            cropImg.release();

            circle(img, Point(box[i].center.x, box[i].center.y), 3, Scalar(0, 255, 0), -1, 8);  //绘制最小外接矩形的中心点
            box[i].points(rect);  //把最小外接矩形四个端点复制给rect数组
            rectangle(img, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
            for(int j=0; j<4; j++)
            {
                line(img, rect[j], rect[(j+1)%4], Scalar(0, 0, 255), 2, 8);  //绘制最小外接矩形每条边
            }
        }



        imshow("USB Camera",img);

        int end = GetTickCount();
        cout<<"当前帧所需时间: "<<end-start<<endl;


        //显示图像
        //imshow("USB Camera",img);
        img.release();
        //decodedObjects.clear();

        int keycode = cv::waitKey(30) & 0xff ; //ESC键退出
        if (keycode == 27) break ;

        switch (keycode) {
        case 's':
            imwrite("save.jpg",img1);
            break;
        default:
            break;
            }
        img1.release();
    }

    cap.release();
    destroyAllWindows() ;
}
发布了56 篇原创文章 · 获赞 26 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qianbin3200896/article/details/103863011
今日推荐