#!/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() ;
}