哈哈,从大一就接触C++,后面自己看书、看视频自学,趁着年轻学东西就很快,自认为已经读过超10万行代码了,也写了很多很多了,之前一直整理在我的私密文章里,用过什么就加进去什么,看了其他同学的博客,忍不住拿出来分享一下,去掉一些带有自己算法的相关程序,仅分享一些基于opencv做项目开发的代码
PS:目前的研究方向是基于深度学习做图像异常检测,欢迎大家互相交流学习~
#include
using namespace std;
int main()
{
cout << "Hello World" << endl;
system("pause");
return 0;
}
createTrackbar(
"滚动条名称",
“窗口名称”,
&变量,
最大范围,
回调函数
);
int createTrackbar(const string& trackbarname, const string&winname, int* value, int count ,TrackbarCallback onChange = 0, void* userdata = 0);
参数1:轨迹条名字
参数2:窗口名字
参数3:滑块初始位置
参数4:表示滑块达到最大位置的值
参数5:默认值为0,指向回调函数
参数6:默认值为0,用户传给回调函数的数据值
#include
#include
using namespace std;
using namespace cv;
void on_track(int lightness, void* usrdata)
{
Mat src = *(Mat*)(usrdata);
Scalar m = Scalar(lightness, lightness, lightness);
Mat dst;
add(src, m, dst);
imshow("亮度", dst);
}
int main()
{
Mat src = imread("lena.png");
int lightness = 50;
int max_value = 100;
Mat dst = Mat::zeros(src.size(), src.type());
Mat m = Mat::zeros(src.size(), src.type());
namedWindow("亮度", WINDOW_FREERATIO);
imshow("亮度", src);
createTrackbar("scroll bar", "亮度", &lightness, max_value, on_track, &src);
waitKey(0);
system("pause");
return 0;
}
while(true)
{
int c = waitKey(100); //视频分析 waitKey(1)
if(c == 27)
{
break;
}
if( c == 49)
{
}
}
void on_draw(int event, int x, int y, int flags, void *userdata)
{
}
#include
using namespace std;
using namespace cv;
struct MouseParam
{
Mat img; //用于画好一个后显示
Mat imgZoomBackup; //用于zoom的还原备份
Mat imgTmp; //用于实时显示
Mat imgBackup; //清空,显示最初的图
Point pt1;
Point pt2;
Rect box;
bool mouseLflag;
};
void draw_rectangle(Mat &img, const Point &pt1, const Point &pt2)
{
//rectangle函数参数: 图片, 左上角, 右下角, 颜色, 线条粗细, 线条类型,点类型
rectangle(img, pt1, pt2, Scalar(0, 255, 0), 1, 0, 0);
}
void on_mouse(int event, int x, int y, int flags, void* param)
{
MouseParam *par = (MouseParam*)param;
Point pt;
pt.x = x;
pt.y = y;
if (event == EVENT_RBUTTONDOWN) //按下右键,重画
{
par->img = par->imgBackup.clone();
}
else if (event == EVENT_LBUTTONDOWN)
{
par->box = Rect2d(x, y, 0, 0);
par->pt1 = pt;
//par->pt2 = pt;
par->mouseLflag = true;
}
else if (event == CV_EVENT_MOUSEMOVE && flags == CV_EVENT_FLAG_LBUTTON)
{
par->pt2 = pt;
par->box.width = x - par->box.x;
par->box.height = y - par->box.y;
}
else if (event == CV_EVENT_LBUTTONUP)
{
par->pt2 = pt;
//draw_rectangle(par->imgTmp, par->pt1, par->pt2);
//par->imgZoomBackup = par->img.clone();
par->mouseLflag = false;
if (par->box.width < 0)
{
par->box.x += par->box.width;
par->box.width *= -1;
}
if(par->box.height < 0)
{
par->box.y += par->box.height;
par->box.height *= -1;
}
rectangle(par->img, par->box, Scalar(0, 0, 255), 1, 1, 0);
}
else if (event == CV_EVENT_MOUSEMOVE)
{
par->pt1 = pt;
//par->img.copyTo(par->imgZoomBackup);
//-1*
}
}
int main()
{
//Mat img(512, 512, CV_8UC3, Scalar::all(255));
Mat img = imread("D:\\program\\data1\\2.png");
MouseParam mouseParam;
mouseParam.img = img.clone();
mouseParam.imgBackup = img.clone();
mouseParam.imgZoomBackup = img.clone();
mouseParam.mouseLflag = false;
namedWindow("Box Example");
//namedWindow("Box Example1");
setMouseCallback("Box Example", on_mouse, &mouseParam);
//imshow(WINNAME, mouseParam.imgTmp);
int key;
while (1)
{
mouseParam.imgTmp = mouseParam.img.clone();
if (mouseParam.mouseLflag == true)
{
rectangle(mouseParam.imgTmp, mouseParam.box, Scalar(255, 0, 255), 1, 1, 0);
}
//draw_rectangle(mouseParam.imgTmp, mouseParam.pt1, mouseParam.pt2);
imshow("Box Example", mouseParam.imgTmp);
//imshow("Box Example1", mouseParam.img);
key = waitKey(40);
}
return 0;
}
#prama once
#include
assert = 0,多半是图像路径不对
Mat src = imread("D:/test/1.png");
if(src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("1", WINDOW_FREERATIO);
imshow("1", src);
waitKey(0);
destroyAllWindows();
return 0;
H - Hue if Color1 is Max H = ( Color2 - Color3 ) / ( Max - Min )
S - Saturation S = (Max - Min ) / Max;
V - Value V = max of either R,G or B
cvtColor(image, gray, COLOR_BGR2GRAY);
opencv支持20多种的颜色转换
index%19 不管多少种,始终在0~18种
int colormap[] =
applyColorMap()
//灰度图像伪彩色增强,彩色图像颜色变换
vector<Mat> mv;
split(image, mv); //通道分离
merge(mv, dst); //通道合并
int from_to[] = {0,2,1,1,2,0];
mixChannels(&image, &dst, 1, from_to, 3); // 3 索引对的数目
inRange(hsv, Scalar(35,43,46), Scalar(77,255,255), mask);
参数1:输入要处理的图像,可以为单通道或多通道。
参数2:包含下边界的数组或标量。
参数3:包含上边界数组或标量。
参数4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
image.copyTo(dst, mask); // mask中不为0的像素拷贝过来
m1 = image.clone();
image.copyTo(m2);
Mat dst = Mat::zeros(Size(m,n), CV_8UC3);
dst = Scalar(127,127,127);
#include
clock_t startTime, endTime;
startTime = clock();//计时开始
endTime = clock();//计时结束
cout << "The run time is: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
#include //for _finddata_t、 _findnext
std::vector<std::string> getFilesList(std::string dir)
{
std::vector<std::string> allPath;
// 在目录后面加上"\\*.*"进行第一次搜索
std::string dir2 = dir + "\\*.*";
intptr_t handle;
_finddata_t findData;
handle = _findfirst(dir2.c_str(), &findData);
if (handle == -1) {// 检查是否成功
std::cout << "can not found the file ... " << std::endl;
return allPath;
}
do
{
if (findData.attrib & _A_SUBDIR) 是否含有子目录
{
//若该子目录为"."或"..",则进行下一次循环,否则输出子目录名,并进入下一次搜索
if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
{
continue;
}
// 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
std::string dirNew = dir + "\\" + findData.name;
std::vector<std::string> tempPath = getFilesList(dirNew);
allPath.insert(allPath.end(), tempPath.begin(), tempPath.end());
}
else //不是子目录,即是文件,则输出文件名和文件的大小
{
std::string filePath = dir + "\\" + findData.name;
std::string fileFormat = filePath.substr(filePath.find_last_of('.') + 1);//获取文件后缀
if (fileFormat == "jpg")
{
//cout << findData.name << endl;
allPath.push_back(filePath);
}
//allPath.push_back(filePath);
//cout << filePath << "\t" << findData.size << " bytes.\n";
}
} while (_findnext(handle, &findData) == 0);
_findclose(handle); // 关闭搜索句柄
return allPath;
}
std::string pattern_jpg = "D:\\program\\imagebases\\*.jpg";
std::vector<cv::String> image_files;
cv::glob(pattern_jpg, image_files);
if (image_files.size() == 0) {
std::cout << "No image files[jpg]" << std::endl;
return 0;
}
for (unsigned int i = 0; i < image_files.size(); i++)
{
Mat template_image = cv::imread(image_files[i]);
}
dstImg.create(search_image.dims, search_image.size, CV_32FC3);
srcImg = imread("flower.jpg");
if (srcImg.empty())
{
printf("could not load image...\n");
return -1;
}
if (src.channels() == 3)
{
cvtColor(src, src_gray, CV_BGR2GRAY);//
// flag >0,三通道,flag = 0,单通道;flag <0, 不转换
}
//像素值的读写
// 彩色图
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
//Vec3b :长度为3的uchar类型的vector向量
Vec3b bgr = src.at<Vec3b>(i,j);
src.at<Vec3b>(i, j)[0] = 0;
src.at<Vec3b>(i, j)[1] = 0;
src.at<Vec3b>(i, j)[2] = 0;
}
}
// 灰度图
for (int i = 0; i < graySrc.rows; i++)
{
for (int j = 0; j < graySrc.cols; j++)
{
graySrc.at<uchar>(i, j) = 255;
}
}
//使用迭代器
MatIterator_<uchar> grayit, grayend;
for ( grayit = graySrc.begin<uchar>(), grayend = graySrc.end<uchar>(); grayit != grayend; grayit++)
{
*grayit = 0;
}
MatIterator_<Vec3b> colorit, colorend;
for (colorit = src.begin<Vec3b>(), colorend =
src.end<Vec3b>(); colorit != colorend; ++colorit)
{
(*colorit)[0] = rand() % 255; //Blue
(*colorit)[1] = rand() % 255; //Green
(*colorit)[2] = rand() % 255; //Red
}
//指针 编译通过,执行出错
for (int i = 0; i < graySrc.rows; i++)
{
//获取第I行首像素指针
uchar *p = graySrc.ptr<uchar>(i);
for (int j = 0; j < graySrc.cols; j++)
{
p[j] = 255;
}
}
for (int i = 0; i < src.rows; ++i)
{
//获取第 i 行首像素指针
Vec3b * p = src.ptr<Vec3b>(i);
for (int j = 0; j < src.cols; ++j)
{
p[j][0] = i % 255; //Blue
p[j][1] = j % 255; //Green
p[j][2] = 0; //Red
}
}
//Mat : row col channel dim
//flag 头文件 opencv: BGR
/* data step[0]:行的数据大小
step[1]: 每个元素的大小
*/
for (int j = 0; j < graySrc.cols; j++)
{
for (int i = 0; i < graySrc.rows; i++)
{
*(graySrc.data + graySrc.step[0] * i + graySrc.step[1] * j) = 255;
}
}
for (int j = 0; j < src.cols; j++)
{
for (int i = 0; i < src.rows; i++)
{
*(src.data + src.step[0] * i + src.step[1] * j ) = 255;
*(src.data + src.step[0] * i + src.step[1] * j + src.elemSize1()) = 255;
*(src.data + src.step[0] * i + src.step[1] * j + src.elemSize1() * 2) = 255;
}
}
//Mat_类 :声明时指明数据类型,使用矩阵元素读写
Mat_<uchar> img = (Mat_<uchar>&)graySrc;
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
img(i, j) = 255;
}
}
Scalar是一个由长度为4的数组作为元素构成的结构体
溢出保护
//
addWeighted(image, 0.7,bg, 0.3, 0, dst);
// 加法
dst = image + Scalar(50,50,50);
add(image, m, dst);
// 减法
substract(image, m ,dst);
// 除法
divide(image, m ,dst);
// 乘法
multipy(image, m2, dst);
// 当运算完之后,结果为负,则转为0,结果超出255,则为255
saturate_cast<uchar>(p1 + p2);
bitwise_and();
bitwise_or();
bitwise_not(); // 非操作
bitwise_xor(); //异或
rectangle(img, Rect(100,100,80,80), Scalar(255,255,0), -1, LINE_8, 0);
/*rect: x, y, w, h
-1 填充 1/2 线宽
LINE_AA:反锯齿
速度:LINE_8>LINE_AA
美观:LINE_AA>LINE_8
*/
circle(image, Point(300,200), 15, Scalar(255,255,0), -1, LINE_8, 0);
// 中心点 半径
line(bg, Point(100,100), Point(200,200), Scalar(255,255,0), 4, LINE_8, 0);
// 椭圆
RotatedRect rrt;
rrt.center = Point(200,200);
rrt.size = Size(100,200);
rrt.angle = 90.0;
ellipse(image, rrt, Scalar(0,255,255),2,8);
true :是否闭合
polylines(img, pts, true, Scalar(0,255,255),2,8,0); //不能进行填充
fillPoly(); //填充
drawContours();
参数 | 说明 |
---|---|
img | 作为画布的矩阵 |
pts | 折线顶点数组 |
isClosed | 是否是闭合折线(多边形) |
color | 折线的颜色 |
thickness | 折线粗细 |
lineType | 线段类型 |
shift | 缩放比例(0是不缩放,4是1/4) |
// 转换格式
img_dist.convertTo(img_dist, CV_8UC1);
//高斯滤波
GaussianBlur(src_gray, src_gray, Size(5, 5), 3);
cv::GaussianBlur(bilater_img, guass_img, cv::Size(5, 5), 3, 3, cv::BORDER_DEFAULT);
int d = 20;
int sigmaColor = 20;
int sigmaSpace = 20;
cv::Mat bilater_img;
bilateralFilter(img, bilater_img, d, sigmaColor, sigmaSpace);
equalizeHist(diff_img, equ_img);
// 伪彩色
applyColorMap(equ_img, im_color, COLORMAP_JET);
threshold(src_diff, src_r, 35, 255, CV_THRESH_BINARY);
threshold(diff_img, bin_img, 0, 255, THRESH_BINARY | THRESH_OTSU);
//自适应阈值分割
int blockSize = 31;
int constValue = 7;
cv::Mat local;
cv::adaptiveThreshold(src_open, local, 255, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);
matchTemplate(search_image, template_image, dstImg, TM_SQDIFF); //归一化互相关
cv::Mat grad_x, grad_y;
cv::Sobel(img, grad_x, CV_8U, 0, 1, 3, 1, 1, BORDER_DEFAULT);
cv::Sobel(img, grad_y, CV_8U, 1, 0, 3, 1, 1, BORDER_DEFAULT);
cv::Canny(dstImg, img_edge, 70, 150, 3);
cv::HoughLinesP(img_dist, lines, 1, CV_PI / 180, 80, 100, 50);
erode(src_gray, src_gray, mask);
dilate(src_gray, src_open, mask);
Mat kernel = getStructuringElement(MORPH_RECT, Size(35, 35), Point(-1, -1)); // MORPH_ELLIPSE
//morphologyEx(src_gray, src_open, CV_MOP_CLOSE, kernel);
// Mat src_open;
morphologyEx(src_gray, src_open, CV_MOP_OPEN, kernel);
// 底帽变换
morphologyEx(src_guass, src_h, CV_MOP_BLACKHAT, kernel);
//图像相减
subtract(src_gray, src_open, src_diff);
cv::absdiff(img, bilater_img, diff_img);
//或运算
bitwise_or(res, dst, res);
double minv, maxv;
Point pt_min, pt_max;
minMaxLoc(imgn, &minv, &maxv, &pt_min, &pt_max);
Mat mean, stddev;
meanStdDev(image, mean,stddev);
四种归一化方法:
如果图像数据类型是32F(32位浮点数)或64F(64位浮点数),则imshow函数内部会自动将每个像素值乘以255并显示,即将原图像素值的范围由[01]映射到[0255](注意:原图像素值必须要归一化)
image.convertTo(dst, CV_32F);
// 像素类型转换后要记得归一化到0~1才能显示
normalize()
cv::distanceTransform(img, img_dist, cv::DIST_L1, cv::DIST_MASK_PRECISE);
vector<vector<Point>> bin_contours;
vector<Vec4i> bin_hireachy;
findContours(img_roi, bin_contours, bin_hireachy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point());
// 删除面积较小的轮廓
contours.erase(std::remove_if(contours.begin(), contours.end(),
[](const std::vector<cv::Point>& c) {return cv::contourArea(c) < 100; }), contours.end());
// 绘制
for (int i = 0; i < contours.size(); i++)
{
//绘制轮廓
cv::drawContours(res, contours, i, cv::Scalar(255, 0, 0), 1, 8, hierarchy);
}
Point2f getRectCenter(Rect rect)
{
Point2f center;
center.x = rect.x + rect.width * 0.5;
center.y = rect.y + rect.height * 0.5;
return center;
}
cv::Point origin;
origin.x = center[i].x + 3;
origin.y = center[i].y - 3;
putText(src, diameter, origin, CV_FONT_HERSHEY_SCRIPT_SIMPLEX, 0.55, Scalar(0, 255, 0));
// 直方图统计
float hist[256] = {0};
for (int i = 0; i < src_gray.rows; i++)
{
for (int j = 0; j < src_gray.cols; j++)
{
int val = src_gray.at<uchar>(i, j);
if (val > 0)
{
hist[val]++;
}
}
}
float hist_prob[256] = { 0 };
int hist_sum = 0;
float hist_sum = accumulate(histm, histm + 256, 0); // 求和
//cout << hist_sum << endl;
for (int k = 0; k < 256; k++)
{
hist_prob[k] = float(histm[k]) / float(hist_sum);
//cout << hist_prob[k] << endl;
}
//分通道显示
vector<Mat> bgr_planes;
split(src, bgr_planes);
//设定像素取值范围
int bins= 256;
float range[] = { 0,256 };
const float *ranges= { range };
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges):
histogram
equalizeHist(gray, hist);
blur(image, dst, Size(3,3), Point(-1,-1));
// Size(3,3)卷积核大小
bilaterFilter(image, dst, 0, 100,10);
//提取图像的骨架
void ImgThin(cv::Mat src, int maxIterations = -1)
{
if (src.empty())
{
return;//图像为空,直接返回
}
//cv::threshold(src, src, m_dThreshold, 1, CV_THRESH_BINARY);//转为0或1的图像
int ImgHeight = src.rows;
int ImgWidth = src.cols;
int count = 0; //记录迭代次数
while (true)
{
count++;
if (maxIterations != -1 && count > maxIterations) //限制次数并且迭代次数到达
break;
vector<pair<int, int> > mFlag; //用于标记需要删除的点
//对点标记
for (int i = 0; i < ImgHeight; ++i)
{
for (int j = 0; j < ImgWidth; ++j)
{
//如果满足四个条件,进行标记
// p9 p2 p3
// p8 p1 p4
// p7 p6 p5
int p1 = src.at<uchar>(i, j);
int p2 = (i == 0) ? 0 : src.at<uchar>(i - 1, j);
int p3 = (i == 0 || j == ImgWidth - 1) ? 0 : src.at<uchar>(i - 1, j + 1);
int p4 = (j == ImgWidth - 1) ? 0 : src.at<uchar>(i, j + 1);
int p5 = (i == ImgHeight - 1 || j == ImgWidth - 1) ? 0 : src.at<uchar>(i + 1, j + 1);
int p6 = (i == ImgHeight - 1) ? 0 : src.at<uchar>(i + 1, j);
int p7 = (i == ImgHeight - 1 || j == 0) ? 0 : src.at<uchar>(i + 1, j - 1);
int p8 = (j == 0) ? 0 : src.at<uchar>(i, j - 1);
int p9 = (i == 0 || j == 0) ? 0 : src.at<uchar>(i - 1, j - 1);
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
{
int ap = 0;
if (p2 == 0 && p3 == 1) ++ap;
if (p3 == 0 && p4 == 1) ++ap;
if (p4 == 0 && p5 == 1) ++ap;
if (p5 == 0 && p6 == 1) ++ap;
if (p6 == 0 && p7 == 1) ++ap;
if (p7 == 0 && p8 == 1) ++ap;
if (p8 == 0 && p9 == 1) ++ap;
if (p9 == 0 && p2 == 1) ++ap;
if (ap == 1)
{
if (p2*p4*p6 == 0)
{
if (p4*p6*p8 == 0)
{
//标记
mFlag.push_back(make_pair(i, j));
}
}
}
}
}
}
//将标记的点删除
for (vector<pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
{
src.at<uchar>(i->first, i->second) = 0;
}
//直到没有点满足,算法结束
if (mFlag.size() == 0) break;
else mFlag.clear();//将mFlag清空
//对点标记
for (int i = 0; i < ImgHeight; ++i)
{
for (int j = 0; j < ImgWidth; ++j)
{
//如果满足四个条件,进行标记
// p9 p2 p3
// p8 p1 p4
// p7 p6 p5
int p1 = src.at<uchar>(i, j);
if (p1 != 1) continue;
int p2 = (i == 0) ? 0 : src.at<uchar>(i - 1, j);
int p3 = (i == 0 || j == ImgWidth - 1) ? 0 : src.at<uchar>(i - 1, j + 1);
int p4 = (j == ImgWidth - 1) ? 0 : src.at<uchar>(i, j + 1);
int p5 = (i == ImgHeight - 1 || j == ImgWidth - 1) ? 0 : src.at<uchar>(i + 1, j + 1);
int p6 = (i == ImgHeight - 1) ? 0 : src.at<uchar>(i + 1, j);
int p7 = (i == ImgHeight - 1 || j == 0) ? 0 : src.at<uchar>(i + 1, j - 1);
int p8 = (j == 0) ? 0 : src.at<uchar>(i, j - 1);
int p9 = (i == 0 || j == 0) ? 0 : src.at<uchar>(i - 1, j - 1);
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
{
int ap = 0;
if (p2 == 0 && p3 == 1) ++ap;
if (p3 == 0 && p4 == 1) ++ap;
if (p4 == 0 && p5 == 1) ++ap;
if (p5 == 0 && p6 == 1) ++ap;
if (p6 == 0 && p7 == 1) ++ap;
if (p7 == 0 && p8 == 1) ++ap;
if (p8 == 0 && p9 == 1) ++ap;
if (p9 == 0 && p2 == 1) ++ap;
if (ap == 1)
{
if (p2*p4*p8 == 0)
{
if (p2*p6*p8 == 0)
{
//标记
mFlag.push_back(make_pair(i, j));
}
}
}
}
}
}
//删除
for (vector<pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
{
src.at<uchar>(i->first, i->second) = 0;
}
//直到没有点满足,算法结束
if (mFlag.size() == 0) break;
else mFlag.clear();//将mFlag清空
}
//cv::threshold(src, src, 0, 255, CV_THRESH_BINARY);//二值化图像
}
roi.setTo(Scalar(255, 255, 255));
assertion failed 可能是显示的图像没赋值
cv::Size dsize = cv::Size(src.cols*scale, src.rows*scale);
cv::resize(src, src, dsize, 0, 0, INTER_LINEAR);
0 上下翻转
1 左右翻转
-1 180°翻转
flip(image,dst,0);
M 两行三列
c o s ( θ ) cos(\theta) cos(θ) | s i n ( θ ) sin(\theta) sin(θ) | 0 |
---|---|---|
− s i n ( θ ) -sin(\theta) −sin(θ) | cos(\theta) | 0 |
M = getROtationMatrix2D(Point2f(), angle, 1.0);
wrapAffine(src, dst, M, dsize, INTER_linear, 0, Scalar(255,255,255));
cv::Point2f get_cross_pts(cv::Vec4i line_1, cv::Vec4i line_2)
{
Point2f crossPoint;
double ka = (double)(line_1[3] - line_1[1]) / (double)(line_1[2] - line_1[0]);//直线的斜率
if (line_2[2] - line_2[0] == 0)
{
crossPoint.x = line_2[0];
crossPoint.y = ka * (line_2[0] - line_1[0]) + line_1[1];
}
else
{
double kb = (double)(line_2[3] - line_2[1]) / (double)(line_2[2] - line_2[0]);//直线的斜率
crossPoint.x = (ka*line_1[0] - line_1[1] - kb*line_2[0] + line_2[1]) / (ka - kb);
crossPoint.y = (ka*kb*(line_1[0] - line_2[0]) + ka*line_2[1] - kb*line_1[1]) / (ka - kb);
}
return crossPoint;
}
// 调用
std::vector<cv::Point2f> cross_pts;
for (int i = 0; i < 2; i++)
{
for (int j = 2; j < 4; j++)
{
Point2f pt = get_cross_pts(border_line[i], border_line[j]);
cross_pts.push_back(pt);
}
}
/**
* @brief 区域生长算法,输入图像应为灰度图像
* @param srcImage 区域生长的源图像
* @param pt 区域生长点
* @param ch1Thres 通道的生长限制阈值,临近像素符合±chxThres范围内才能进行生长
* @param ch1LowerBind 通道的最小值阈值
* @param ch1UpperBind 通道的最大值阈值,在这个范围外即使临近像素符合±chxThres也不能生长
* @return 生成的区域图像(二值类型)
*/Mat RegionGrow(Mat srcImage, Point pt, int ch1Thres, int ch1LowerBind = 0, int ch1UpperBind = 255) {
Point pToGrowing; //待生长点位置
int pGrowValue = 0; //待生长点灰度值
Scalar pSrcValue = 0; //生长起点灰度值
Scalar pCurValue = 0; //当前生长点灰度值
Mat growImage = Mat::zeros(srcImage.size(), CV_8UC1); //创建一个空白区域,填充为黑色
//生长方向顺序数据
int DIR[8][2] = { { -1,-1 },{ 0,-1 },{ 1,-1 },{ 1,0 },{ 1,1 },{ 0,1 },{ -1,1 },{ -1,0 } };
vector<Point> growPtVector; //生长点栈
growPtVector.push_back(pt); //将生长点压入栈中
growImage.at<uchar>(pt.y, pt.x) = 255; //标记生长点
pSrcValue = srcImage.at<uchar>(pt.y, pt.x); //记录生长点的灰度值
while (!growPtVector.empty()) //生长栈不为空则生长
{
pt = growPtVector.back(); //取出一个生长点
growPtVector.pop_back(); //分别对八个方向上的点进行生长
for (int i = 0; i<9; ++i)
{
pToGrowing.x = pt.x + DIR[i][0];
pToGrowing.y = pt.y + DIR[i][1]; //检查是否是边缘点
if (pToGrowing.x < 0 || pToGrowing.y < 0 ||
pToGrowing.x >(srcImage.cols - 1) || (pToGrowing.y > srcImage.rows - 1)) continue;
pGrowValue = growImage.at<uchar>(pToGrowing.y, pToGrowing.x); //当前待生长点的灰度值
pSrcValue = srcImage.at<uchar>(pt.y, pt.x); if (pGrowValue == 0) //如果标记点还没有被生长
{
pCurValue = srcImage.at<uchar>(pToGrowing.y, pToGrowing.x); if (pCurValue[0] <= ch1UpperBind && pCurValue[0] >= ch1LowerBind)
{
if (abs(pSrcValue[0] - pCurValue[0]) < ch1Thres) //在阈值范围内则生长
{
growImage.at<uchar>(pToGrowing.y, pToGrowing.x) = 255; //标记为白色
growPtVector.push_back(pToGrowing); //将下一个生长点压入栈中
}
}
}
}
} return growImage.clone();
}
cv::Mat coord_wrap(cv::Mat &img, std::vector<cv::Point2f> pts_src)
{
/*int pad = 0;
*/
Point2f pt1 = pts_src[0];
Point2f pt2 = pts_src[1];
Point2f pt3 = pts_src[2];
std::vector<cv::Point2f> pts_dst;
int w = sqrt(pow(pt2.x - pt1.x, 2) + pow(pt2.y - pt1.y, 2));
int h = sqrt(pow(pt1.x - pt3.x, 2) + pow(pt1.y - pt3.y, 2));
pts_dst.push_back(cv::Point2f(0, 0));
pts_dst.push_back(cv::Point2f(w, 0));
pts_dst.push_back(cv::Point2f(0, h));
pts_dst.push_back(cv::Point2f(w, h));
cv::Mat H = cv::findHomography(pts_src, pts_dst);
cv::Mat im_out;
cv::warpPerspective(img, im_out, H, cv::Size(w, h));
return im_out;
}
copyMakeBorder(canny_edges, mask, 0, 2, 0, 2, 0, Scalar(0));
void border_padding(cv::Mat &img, int pad, cv::Mat& res)
{
int width = img.cols;
int height = img.rows;
int res_width = width + 2 * pad;
int res_height = height + 2 * pad;
res.create(res_height, res_width, img.type());
int val = 255;
for (int i = 0; i < height + 2 * pad; i++)
{
cv::Vec3b *p = res.ptr<cv::Vec3b>(i);//彩色
for (int j = 0; j < width + 2 * pad; j++)
{
cv::Vec3b &pix = *p++;//彩色图
if (i < pad || i >= height + pad || j < pad || j >= width + pad)
{
pix[0] = 255;
pix[1] = 255;
pix[2] = 255;
}
else
{
pix[0] = img.at<cv::Vec3b>(i - pad, j - pad)[0];
pix[1] = img.at<cv::Vec3b>(i - pad, j - pad)[1];
pix[2] = img.at<cv::Vec3b>(i - pad, j - pad)[2];
}
}
}
}
Point seed = Point(800, 600);
int loDiff = 5;
int upDiff = 5;
Scalar newVal = Scalar(0, 0, 255);
Mat mask = Mat::zeros(img.rows + 2, img.cols + 2, CV_8UC1);
//copyMakeBorder(canny_edges, mask, 0, 2, 0, 2, 0, Scalar(0));
Rect ccomp;
int flg = 8;
floodFill(src, mask, seed, newVal, &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flg);//避免边缘被填充
#include
#include "global.h"
using namespace cv;
struct MouseParam
{
Mat img;
Mat g_image_show;//用于画好一个后显示
Mat imgZoom; //缩放图像
Mat imgTmp; //实时显示图像
Point g_location_win; //鼠标相对于窗口的坐标
Point location_win; //窗口相对于图片的坐标
Point pt1; //鼠标右键单击的位置
Point pt2;//鼠标右键释放的位置
Point show_wh; //实际显示图片的宽高
bool mouseLflag;
float g_zoom;
};
//计算窗口在图像中的位置
// win_xy : 窗口在图片的位置
void calLocation(Point win_xy, int src_width, int src_height, int window_width, int window_height)
{
//int window_width = windowSize.x;
//int window_height = windowSize.y;
if (win_xy.x < 0)
{
win_xy.x = 0;
}
else if (win_xy.x + window_width > src_width && window_width < src_width)
{
win_xy.x = src_width - window_width;
}
else if (win_xy.x + window_width > src_width && window_width > src_width)
{
win_xy.x = 0;
}
if (win_xy.y < 0)
{
win_xy.y = 0;
}
else if (win_xy.y + window_height > src_height && window_height < src_height)
{
win_xy.y = src_height - window_height;
}
else if (win_xy.x + window_height > src_height && window_height > src_height)
{
win_xy.y = 0;
}
}
// 计算缩放倍数
// flag:鼠标滚轮上移或下移的标识, step:缩放系数,滚轮每步缩放0.1, zoom:缩放倍数
float calZoom(int flag, int step, float zoom)
{
if (flag > 0) //滚轮前移
{
zoom = zoom + step;
if (zoom > 1 + step * 20)
{
zoom = 1 + step * 20; //最多只能放大3倍
}
}
else if (flag < 0)
{
zoom = zoom - step;
if (zoom < step)
{
zoom = step; //最多只能缩小到0.1
}
}
return zoom;
}
void on_mouse(int event, int x, int y, int flags, void* param)
{
MouseParam *par = (MouseParam*)param;
Point click_location(x, y); //鼠标点击的位置
if (event == EVENT_RBUTTONDOWN) //右键点击
{
par->pt1 = click_location;
par->location_win.x = par->g_location_win.x;
par->location_win.y = par->g_location_win.y;
}
else if (event == CV_EVENT_MOUSEMOVE && flags == CV_EVENT_FLAG_RBUTTON) //按住且拖拽
{
par->pt2 = click_location;
//Mat imgzoom = par->imgZoom;
int w1 = par->imgZoom.cols; //缩放图像的宽高
int h1 = par->imgZoom.rows;
int w2 = 800;
int h2 = 600;
par->show_wh.x = 0;
par->show_wh.y = 0;
if (w1 < w2 && h1 < h2) //图片的宽高小于窗口宽高,无法移动
{
par->show_wh.x = w1;
par->show_wh.y = h1;
par->g_location_win.x = 0;
par->g_location_win.y = 0;
}
else if (w1 >= w2 && h1 < h2) //图片的宽度大于窗口的宽度,可左右移动
{
par->show_wh.x = w2;
par->show_wh.y = h1;
par->g_location_win.x = par->location_win.x + par->pt1.x - par->pt2.x;
//par->g_location_win.y = 0;
}
else if (w1 < w2 && h1 >= h2) //图片的高度大于窗口的高度,可上下移动
{
par->show_wh.x = w1;
par->show_wh.y = h2;
par->g_location_win.y = par->location_win.y + par->pt1.y - par->pt2.y;
//par->g_location_win.y = 0;
}
else //图片的宽高大于窗口宽高,可左右上下移动
{
par->show_wh.x = w2;
par->show_wh.y = h2;
par->g_location_win.x = par->location_win.x + par->pt1.x - par->pt2.x;
par->g_location_win.y = par->location_win.y + par->pt1.y - par->pt2.y;
}
calLocation(par->g_location_win, w1, h1, w2, h2); // 矫正窗口在图片中的位置
int x2 = par->g_location_win.x + par->show_wh.x;
int y2 = par->g_location_win.y + par->show_wh.y;
Rect g_image_zoom(par->g_location_win, Point(x2, y2));
par->g_image_show = par->img(g_image_zoom).clone();
}
else if (event == CV_EVENT_MOUSEWHEEL)
{
float z = par->g_zoom;
float gzoom = calZoom(flags, step, z);
//缩放后图片的宽高
int w1 = (int)(par->img.cols*gzoom );
int h1 = (int)(par->img.rows*gzoom );
//窗口的宽高
int w2 = 800;
int h2 = 600;
Point pt(0, 0);
par->show_wh = pt;
resize(par->img, par->g_image_show, Size(), gzoom, gzoom, INTER_LINEAR); //图片缩放
if (w1 < w2 && h1 < h2) //缩放后,图片宽高小于窗口宽高
{
par->show_wh.x = w1;
par->show_wh.y = h1;
resizeWindow("1", w1, h1);
}
else if (w1 >= w2 && h1 < h2) //缩放后,图片高度小于窗口高度
{
par->show_wh.x = w2;
par->show_wh.y = h1;
resizeWindow("1", w2, h1);
}
else if (w1 < w2 && h1 >= h2) //缩放后,图片宽度小于窗口宽度
{
par->show_wh.x = w1;
par->show_wh.y = h2;
resizeWindow("1", w1, h2);
}
else //缩放后,图片宽高大于窗口宽高
{
par->show_wh.x = w2;
par->show_wh.y = h2;
resizeWindow("1", w2, h2);
}
//缩放后,窗口在图片的位置
par->g_location_win.x = (int)(par->g_location_win.x + x) * gzoom / z - x;
par->g_location_win.y = (int)(par->g_location_win.y + y) * gzoom / z - y;
calLocation(par->g_location_win, w1, h1, w2, h2);
int x2 = par->g_location_win.x + par->show_wh.x;
int y2 = par->g_location_win.y + par->show_wh.y;
Rect g_image_zoom(par->g_location_win, Point(x2, y2));
par->g_image_show = par->img(g_image_zoom).clone();
}
imshow("1", par->g_image_show);
}
int main()
{
Mat src = imread("D:\\program\\data1\\2.png");
int src_width = src.rows;
int src_height = src.cols;
MouseParam mouseParam;
mouseParam.img = src.clone();
//mouseParam.imgTmp = src.clone();
mouseParam.g_image_show = src.clone();
/*src.copyTo(mouseParam.img);
src.copyTo(mouseParam.imgTmp);
src.copyTo(mouseParam.g_image_show);*/
mouseParam.g_zoom = 1.0;
Point pt(0, 0);
mouseParam.g_location_win = pt;
mouseParam.location_win = pt;
/*int x2 = mouseParam.g_location_win.x +800;
int y2 = mouseParam.g_location_win.y + 600;
Rect g_image_zoom(mouseParam.g_location_win, Point(x2, y2));
mouseParam.g_image_show = mouseParam.img(g_image_zoom).clone();*/
Point win_xy;
Point windowSize(800, 600); //设定窗口的尺寸
namedWindow("1", CV_WINDOW_NORMAL);
resizeWindow("1", windowSize.x, windowSize.y);
setMouseCallback("1", on_mouse, &mouseParam);
//while (1)
//{
// mouseParam.imgTmp = mouseParam.img.clone();
imshow("1", mouseParam.g_image_show);
// int k = waitKey(40);
//}
//imshow("1", src);
waitKey(0);
//int k = waitKey(40);
return 0;
}
#include
using namespace std;
using namespace cv;
struct MouseParam
{
Mat img; //用于画好一个后显示
Mat imgZoomBackup; //用于zoom的还原备份
Mat imgTmp; //用于实时显示
Mat imgBackup; //清空,显示最初的图
Point pt1;
Point pt2;
Rect box;
bool mouseLflag;
};
void draw_rectangle(Mat &img, const Point &pt1, const Point &pt2)
{
//rectangle函数参数: 图片, 左上角, 右下角, 颜色, 线条粗细, 线条类型,点类型
rectangle(img, pt1, pt2, Scalar(0, 255, 0), 1, 0, 0);
}
void on_mouse(int event, int x, int y, int flags, void* param)
{
MouseParam *par = (MouseParam*)param;
Point pt;
pt.x = x;
pt.y = y;
if (event == EVENT_RBUTTONDOWN) //按下右键,重画
{
par->img = par->imgBackup.clone();
}
else if (event == EVENT_LBUTTONDOWN)
{
par->box = Rect2d(x, y, 0, 0);
par->pt1 = pt;
//par->pt2 = pt;
par->mouseLflag = true;
}
else if (event == CV_EVENT_MOUSEMOVE && flags == CV_EVENT_FLAG_LBUTTON)
{
par->pt2 = pt;
par->box.width = x - par->box.x;
par->box.height = y - par->box.y;
}
else if (event == CV_EVENT_LBUTTONUP)
{
par->pt2 = pt;
//draw_rectangle(par->imgTmp, par->pt1, par->pt2);
//par->imgZoomBackup = par->img.clone();
par->mouseLflag = false;
if (par->box.width < 0)
{
par->box.x += par->box.width;
par->box.width *= -1;
}
if(par->box.height < 0)
{
par->box.y += par->box.height;
par->box.height *= -1;
}
rectangle(par->img, par->box, Scalar(0, 0, 255), 1, 1, 0);
}
else if (event == CV_EVENT_MOUSEMOVE)
{
par->pt1 = pt;
//par->img.copyTo(par->imgZoomBackup);
//-1*
}
}
int main()
{
//Mat img(512, 512, CV_8UC3, Scalar::all(255));
Mat img = imread("D:\\program\\data1\\2.png");
MouseParam mouseParam;
mouseParam.img = img.clone();
mouseParam.imgBackup = img.clone();
mouseParam.imgZoomBackup = img.clone();
mouseParam.mouseLflag = false;
namedWindow("Box Example");
//namedWindow("Box Example1");
setMouseCallback("Box Example", on_mouse, &mouseParam);
//imshow(WINNAME, mouseParam.imgTmp);
int key;
while (1)
{
mouseParam.imgTmp = mouseParam.img.clone();
if (mouseParam.mouseLflag == true)
{
rectangle(mouseParam.imgTmp, mouseParam.box, Scalar(255, 0, 255), 1, 1, 0);
}
//draw_rectangle(mouseParam.imgTmp, mouseParam.pt1, mouseParam.pt2);
imshow("Box Example", mouseParam.imgTmp);
//imshow("Box Example1", mouseParam.img);
key = waitKey(40);
}
return 0;
}
bool createFolder(CString m_sCurPath)
{
CString folderPath = m_sCurPath + "//labels";
//判断目录是否存在,如果不存在,则创建一个
if (_access(folderPath, 0) != 0)
{
int flag = CreateDirectory(folderPath, NULL);
//判断目录是否创建成功 非零表示成功,零表示失败。
if (flag != 0)
{
return true;
}
else
{
return false;
}
}
return true;
}
bool saveBox(BoxList boxList, CString m_sCurPath)
{
CString folderPath = m_sCurPath + "//labels";
if (_access(folderPath, 0) == -1) //不存在,返回-1
{
createFolder(m_sCurPath);
}
CString FilefullName = boxList.fileName;
int nPos = FilefullName.ReverseFind('.');
CString csFileName = FilefullName.Left(nPos); // 获取文件名,去掉扩展名
CString FILENAME = folderPath + "//" + csFileName + ".txt";
std::ofstream ofs;
ofs.open(FILENAME, std::ios::out);//用输出的方式打开文件 --写文件
std::vector<labelBox> bbox = boxList.boundingbox;
//将每个边界框的数据写入文件
for (int i = 0; i < bbox.size(); i++)
{
ofs << bbox[i].className << " "
<< bbox[i].boundingbox.x << " "
<< bbox[i].boundingbox.y << " "
<< bbox[i].boundingbox.width << " "
<< bbox[i].boundingbox.height << std::endl;
}
//关闭文件
ofs.close();
//判断文件是否存在
if (_access(FILENAME, 0) != -1) //不存在,返回-1
{
return true;
}
else
{
return false;
}
}
VideoCapture capture(1);
// 0 是我的前摄像头,1是我的后摄像头
Mat frame;
while (true)
{
capture.read(frame);
flip(frame, frame, 1);
if (frame.empty())
{
break;
}
imshow("frame", frame);
int c = waitKey(10);
if (c == 27)
{
break;
}
capture.release();
}
int framw_width = capture.get(CAP_PROP_FRAME_WIDTH);
int count = capture.get(CAP_PROP_FRAME_COUNT);
// 帧数
int fps = capture.get(CAP_PROP_FPS);
保存视频一般不超过2G
VideoWriter writer("VideoTest.avi", capture.get(CAP_CV_FOURCC), 25.0, Size(640, 480));
writer.writer(frame);
opencv4.4.0
#include