#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { int startf = 39, endf = 512; // 视频帧的起始和结束帧号 // 读入背景图像 Mat Ibj = imread("D://yanyi//opencv//test//opencv1//BackgroundFrame.jpg", IMREAD_GRAYSCALE); for (int i = startf; i <= endf; i++) // 遍历视频帧 { // 读入当前视频帧并转化为灰度图像 Mat I1 = imread("frame" + to_string(i) + ".jpg"); Mat gray; cvtColor(I1, gray, COLOR_BGR2GRAY); // 将灰度图像转换为双精度浮点型并减去背景图像 gray.convertTo(gray, CV_64F); gray -= Ibj; // 对图像进行二值化处理 Mat bw1; threshold(gray, bw1, 25, 255, THRESH_BINARY); // 对二值化图像进行形态学开运算 Mat bwAreaOpenBW; morphologyEx(bw1, bwAreaOpenBW, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(3, 3))); // 对二值化图像进行连通组件分析 Mat labels; if (bwAreaOpenBW.depth() != CV_8U && bwAreaOpenBW.depth() != CV_8S) { bwAreaOpenBW.convertTo(bwAreaOpenBW, CV_8U); // or CV_8S } int n = connectedComponents(bwAreaOpenBW, labels, 8, CV_16U); // 遍历每一个连通组件 for (int j = 1; j < n; j++) { // 提取连通组件中的像素点 Mat mask = labels == j; vector<Point> points; findNonZero(mask, points); // 构建矩阵并求解线性方程组 Mat X(points.size(), 2, CV_64F); for (int k = 0; k < points.size(); k++) { X.at<double>(k, 0) = points[k].x; X.at<double>(k, 1) = points[k].y; } Mat Y(points.size(), 1, CV_64F); for (int k = 0; k < points.size(); k++) { Y.at<double>(k, 0) = points[k].y; } Mat coef; solve(X, Y, coef, DECOMP_SVD); // 计算轴的两个端点的坐标 double b1 = coef.at<double>(0, 0); double b2 = coef.at<double>(1, 0); double minzhi = points[0].x; double maxzhi = points[0].x; for (int k = 1; k < points.size(); k++) { if (points[k].x < minzhi) { minzhi = points[k].x; } if (points[k].x > maxzhi) { maxzhi = points[k].x; } } double duan1x = b1 + b2 * minzhi; double duan1y = minzhi; double duan2x = b1 + b2 * maxzhi; double duan2y = maxzhi; // 在图像上绘制轴的两个端点 circle(I1, Point(duan1x, duan1y), 3, Scalar(0, 0, 255), -1); circle(I1, Point(duan2x, duan2y), 3, Scalar(0, 0, 255), -1); } // 显示处理结果并等待用户按键 imshow("result", I1); waitKey(1); } return 0; }没有绘制出端点是怎么回事
在您的代码中,绘制了轴的两个端点,但是没有将它们绘制在原始图像上,而是绘制在处理结果I1上。因此,当最后显示处理结果时,只显示了处理结果I1,而没有显示原始图像。
要绘制端点并显示在原始图像上,可以将绘制端点的代码移动到以下位置:
// 在图像上绘制轴的两个端点
circle(I1, Point(duan1x, duan1y), 3, Scalar(0, 0, 255), -1);
circle(I1, Point(duan2x, duan2y), 3, Scalar(0, 0, 255), -1);
// 显示处理结果并等待用户按键
imshow("result", I1);
waitKey(1);
在这个位置上,绘制了端点后,将它们显示到了原始图像I1中,而不是处理结果I1。
请注意,此代码只绘制了端点,并没有将它们连接成一条直线。如果您希望画出直线,请尝试使用cv::line函数。
#include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> using namespace std; using namespace cv; #include <opencv2/wechat_qrcode.hpp> int main() { const std::string modelDir = R"(D:\opencv\opencv4.5.4\build_contrib\downloads\wechat_qrcode\)"; // 构造(使用异常捕获构造函数是否正常) wechat_qrcode::WeChatQRCode detector{ modelDir + "detect.prototxt", modelDir + "detect.caffemodel", modelDir + "sr.prototxt", modelDir + "sr.caffemodel" }; // 临时变量 Mat img; vector<Mat> points; // qrcode: Retangle, not RotatedBox auto camIdx = 0; // auto camIdx = R"(C:\Users\wanggao\Desktop\qrconde_test.jpg)"; VideoCapture cap(camIdx); while(cap.read(img)){ // 检测 auto res = detector->detectAndDecode(img, points); // 结果叠加 for(size_t idx = 0; idx < res.size(); idx ++){ Point pt1 = points[idx].at<Point2f>(0); Point pt2 = points[idx].at<Point2f>(2); Rect rect{pt1, pt2}; Point center = (pt1 + pt2) / 2; // 绘制矩形框 rectangle(img, rect, {0,0,255}, 2); circle(img, center, rect.height / 15, {0,0,255}, -1); // 解码字符串 putText(img, res[idx], {pt1.x, pt2.y + 16}, 1, 1, {0,0,255}); } imshow("image", img); if (waitKey(30) >= 0) break; } return 0; } 为什么detector->detectAndDecode这句话调用几次后会导致程序崩溃
这个问题可能是由于内存泄漏导致的。在循环中多次调用detectAndDecode
函数,每次调用都会分配一些内存,如果没有及时释放这些内存,就会导致内存耗尽,最终导致程序崩溃。
有两种方法可以解决这个问题:
在循环中每次调用
detectAndDecode
函数之前,先释放上一次调用生成的内存。可以使用points.clear()
和res.clear()
清空上一次调用生成的内存,或者使用points.resize(0)
和res.resize(0)
将向量的大小重置为0。将
detector
对象定义在循环外部,避免多次构造和析构。可以将detector
对象定义为全局变量或静态变量,或者将其定义在main
函数的外部。
下面是第一种方法的修改后的代码:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
#include <opencv2/wechat_qrcode.hpp>
int main()
{
const std::string modelDir = R"(D:\opencv\opencv4.5.4\build_contrib\downloads\wechat_qrcode\)";
// 构造(使用异常捕获构造函数是否正常)
wechat_qrcode::WeChatQRCode detector{
modelDir + "detect.prototxt",
modelDir + "detect.caffemodel",
modelDir + "sr.prototxt",
modelDir + "sr.caffemodel"
};
// 临时变量
Mat img;
vector<Mat> points;
vector<string> res;
auto camIdx = 0;
// auto camIdx = R"(C:\Users\wanggao\Desktop\qrconde_test.jpg)";
VideoCapture cap(camIdx);
while(cap.read(img)){
// 检测
detector->detectAndDecode(img, points, res);
// 结果叠加
for(size_t idx = 0; idx < res.size(); idx ++){
Point pt1 = points[idx].at<Point2f>(0);
Point pt2 = points[idx].at<Point2f>(2);
Rect rect{pt1, pt2};
Point center = (pt1 + pt2) / 2;
// 绘制矩形框
rectangle(img, rect, {0,0,255}, 2);
circle(img, center, rect.height / 15, {0,0,255}, -1);
// 解码字符串
putText(img, res[idx], {pt1.x, pt2.y + 16}, 1, 1, {0,0,255});
}
imshow("image", img);
if (waitKey(30) >= 0)
break;
// 释放内存
points.resize(0);
res.resize(0);
}
return 0;
}
在这个修改后的代码中,每次调用detectAndDecode
函数之前,都会将points
和res
向量的大小重置为0,以释放上一次调用生成的内存。
#include<opencv2/opencv.hpp> #include<iostream> #include <string> using namespace cv; void ImageThreshold(String str) { Mat image = imread(str); Mat binary; cvtColor(image, binary, COLOR_BGR2GRAY); imshow("test_opencv_srtup", binary); waitKey(0); } int main() { String str = "壁纸3.jpg"; // 注意文件路径和你所对应的图片 ImageThreshold(str); return 0; }
这是一个使用OpenCV库进行图像处理的程序。
程序首先包含了必要的头文件,包括OpenCV的头文件、iostream和string。然后定义了一个ImageThreshold函数,该函数的作用是将输入的图像进行二值化处理并显示出来。
在main函数中,先定义了一个字符串str,指定了要处理的图像文件名。然后调用ImageThreshold函数对图像进行处理。处理完成后,程序返回0结束运行。
注意到程序中的代码将图像读入为BGR格式的彩色图像,然后将其转换为灰度图像,并显示出来。这里使用了OpenCV中的imread函数读取图像,cvtColor函数对图像进行颜色空间转换,imshow函数显示图像,waitKey函数等待键盘输入。
相关推荐















