opencv4集成了二维码检测功能测试一下
代码很简单:
#include
#include
using namespace cv;
int main()
{
//读取本地的一张图片便显示出来
cv::Mat img = imread("45.jpg");
cv::QRCodeDetector QRdetecter;
std::vector list;
cv::Mat res;
QRdetecter.detectAndDecode(img, list, res);
for (int i = 0; i < list.size(); i++)
{
if (i == 3)
line(img, list[i], list[0], Scalar(0, 255, 0), 2);
else
line(img, list[i], list[i + 1], Scalar(0, 255, 0), 2);
}
imshow("测试窗口", img);
waitKey(0);
return 0;
}
效果:
之前的二维码都是自己实现的功能,opencv4的简直又快又好。
自己实现:
#include
#include
#include
using namespace cv;
using namespace std;
using namespace zbar;
Mat GammaTransform(cv::Mat &image)
{
Mat imageGamma;
Mat dist;
//灰度归一化
image.convertTo(imageGamma, CV_64F, 1.0 / 255, 0);
//伽马变换
double gamma = 1.5;
pow(imageGamma, gamma, dist);//dist 要与imageGamma有相同的数据类型
dist.convertTo(dist, CV_8U, 255, 0);
return dist;
}
int main(int argc, char* argv[])
{
char fileNameString[100];
char windowNameString[50];
char resultFileNameSring[100];
Mat srcImage, grayImage, blurImage, thresholdImage, gradientXImage, gradientYImage, gradientImage, morphImage;
for (int fileCount = 1; fileCount < 8; fileCount++)
{
//读取图像
srcImage = imread("67.jpg");
if (srcImage.empty())
{
cout << "image file read error" << endl;
return -1;
}
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", srcImage);
srcImage = GammaTransform(srcImage);
namedWindow("伽马", WINDOW_NORMAL);
imshow("伽马", srcImage);
//图像转换为灰度图像
if (srcImage.channels() == 3)
{
cvtColor(srcImage, grayImage, COLOR_RGB2GRAY);
namedWindow("灰度化", WINDOW_NORMAL);
imshow("灰度化", grayImage);
}
else
{
grayImage = srcImage.clone();
}
blur(grayImage, blurImage, Size(5, 5));
//模糊化以后进行阈值化,得到到对应的黑白二值化图像,二值化的阈值可以根据实际情况调整
threshold(blurImage, thresholdImage, 210, 255, 8);
bitwise_not(thresholdImage, thresholdImage);
namedWindow("大津二值化", WINDOW_NORMAL);
imshow("大津二值化", thresholdImage);
//看看二值化图像
//imshow(windowNameString,thresholdImage);
//二值化以后的图像,条形码之间的黑白没有连接起来,就要进行形态学运算,消除缝隙,相当于小型的黑洞,选择闭运算
//因为是长条之间的缝隙,所以需要选择宽度大于长度
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 3));
morphologyEx(thresholdImage, morphImage, MORPH_CLOSE, kernel);
//看看形态学操作以后的图像
//imshow(windowNameString,morphImage);
//现在要让条形码区域连接在一起,所以选择膨胀腐蚀,而且为了保持图形大小基本不变,应该使用相同次数的膨胀腐蚀
//先腐蚀,让其他区域的亮的地方变少最好是消除,然后膨胀回来,消除干扰,迭代次数根据实际情况选择
dilate(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(5, 5)), Point(-1, -1), 3);
erode(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(3, 3)), Point(-1, -1), 4);
namedWindow("形态学", WINDOW_NORMAL);
imshow("形态学", morphImage);
//看看形态学操作以后的图像
//imshow(windowNameString,morphImage);
vector>contours;
vectorcontourArea;
//接下来对目标轮廓进行查找,目标是为了计算图像面积
findContours(morphImage, contours, RETR_CCOMP, CHAIN_APPROX_NONE);
//计算轮廓的面积并且存放
for (int i = 0; i < contours.size(); i++)
{
contourArea.push_back(cv::contourArea(contours[i]));
}
////找出面积最大的轮廓
//double maxValue; Point maxLoc;
//minMaxLoc(contourArea, NULL, &maxValue, NULL, &maxLoc);
////计算面积最大的轮廓的最小的外包矩形
//RotatedRect minRect = minAreaRect(contours[maxLoc.x]);
int index = 0;
if (!contours.empty())
{
for (std::vector >::iterator it = contours.begin(); it != contours.end();)
{
if (fabs(cv::contourArea(Mat(*it))) < morphImage.cols * morphImage.rows / 15 || fabs(cv::contourArea(Mat(*it))) > morphImage.cols * morphImage.rows *0.8)
{
it = contours.erase(it);
}
else
{
it++;
}
}
for (std::vector >::iterator it = contours.begin(); it != contours.end();)
{
RotatedRect rr = minAreaRect(*it);
float w = rr.size.width;
float h = rr.size.height;
//根据长宽比删选
if (w >= h)
{
w = rr.size.height;
h = rr.size.width;
}
if (w/h>1.2 || w/h <0.86)
{
it = contours.erase(it);
}
else
{
it++;
}
}
if (!contours.empty())
{
Mat draw = Mat::zeros(morphImage.size(), CV_8UC3);
Mat draw2 = Mat::zeros(morphImage.size(), CV_8UC1);
drawContours(draw, contours,
-1, // draw all contours
Scalar(255, 0, 0), // in white
-1, 8); // with a thickness of 2
namedWindow("Contours 筛选", WINDOW_NORMAL);
imshow("Contours 筛选", draw);
drawContours(draw2, contours,
-1, // draw all contours
Scalar(255, 255, 255), // in white
-1, 8); // with a thickness of 2
namedWindow("Contours ", WINDOW_NORMAL);
imshow("Contours", draw2);
//https://blog.csdn.net/kakiebu/article/details/79114964
//https://blog.csdn.net/mangobar/article/details/79711335
//放射变换
RotatedRect mr = minAreaRect(Mat(contours[0]));
Mat DrawImg(draw2.size(), draw2.type(), Scalar(0));
Point2f vectpoint[4];
mr.points(vectpoint);
for (int i = 0; i<4; i++)
{
line(DrawImg, vectpoint[i], vectpoint[(i + 1) % 4], Scalar(255, 0, 0), 2);
}
imshow("drawimg", DrawImg);
//waitKey();
float angle = 0.0;
Size si = mr.size;
if (mr.size.width <= mr.size.height)
{
angle = mr.angle + 90;
int tm = si.width;
si.width = si.height;
si.height = tm;
//swap(si.width, si.height);
}
else
{
angle = mr.angle;
}
Mat rotmat = getRotationMatrix2D(mr.center, angle, 1);
Mat deal_img;
warpAffine(srcImage, srcImage, rotmat, draw2.size(), INTER_CUBIC);
warpAffine(draw2, deal_img, rotmat, draw2.size(), INTER_CUBIC);
imshow("旋转矫正0", srcImage);
imshow("旋转矫正", deal_img);
if(deal_img.channels()==3)
cvtColor(deal_img, deal_img, COLOR_BGR2GRAY);
vector>contours2;
//接下来对目标轮廓进行查找,目标是为了计算图像面积
findContours(deal_img, contours2, RETR_EXTERNAL, CHAIN_APPROX_NONE);
//计算轮廓的面积并且存放
if (!contours2.empty())
{
Mat roi;
for (std::vector >::iterator it = contours.begin(); it != contours.end();it++)
{
Rect rec = boundingRect(Mat(*it));
roi = srcImage(rec);
imshow("roi", roi);
}
ImageScanner scanner;
scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
Mat imageGray;
cvtColor(roi, imageGray, COLOR_RGB2GRAY);
int width = imageGray.cols;
int height = imageGray.rows;
uchar *raw = (uchar *)imageGray.data;
Image imageZbar(width, height, "Y800", raw, width * height);
scanner.scan(imageZbar); //扫描条码
Image::SymbolIterator symbol = imageZbar.symbol_begin();
if (imageZbar.symbol_begin() == imageZbar.symbol_end())
{
cout << "查询条码失败,请检查图片!" << endl;
}
for (; symbol != imageZbar.symbol_end(); ++symbol)
{
cout << "类型:" << endl << symbol->get_type_name() << endl << endl;
cout << "条码:" << endl << symbol->get_data() << endl << endl;
}
//imshow("Source Image", resultImage);
waitKey();
}
}
}
}
waitKey(0);
getchar();
return 1;
}
推荐一个自己实现的,可供学习:https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html