关键标注以及关键点热力图一键生成工具
作者:互联网
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、开发流程
- 二、开发步骤
- 总结
- *
- **注意:由于C++中OpenCV的像素类型为uchar即为8u1c,如果直接让热力图等于0-1之间的一个概率C++直接默认小数等于0,所以在生成热力图时将热力图每个像素扩大了100倍。 不足:之所以没有使用python编程是因为python中OpenCV在读取和保存图像时直接将小数点后舍去了,如何让OpenCV读取小数并且不进行舍入目前没有办法解决,有一个想法是把每个热力图的像素存在文件中之后在进行网络训练时由文件读取到numpy数组里面,但是如果那样工作量就太大了因此放弃。第二个不足之处在于opencv默认的像素的xy轴与我们一般认为的xy轴不太一样,是直接使用了像素坐标系的表示,因此在标注时的关键点位置与热力图位置看起来不一样,不过没关系因为像素坐标在坐标系的位置其实是一样。**
前言
由之前的工作计划,使用摄像头采集数据并训练神经网络来预测物体的特征点,目前的想法是采用FCN或者UNET来构建特征点检测网络。而该步骤的第一部分为构建数据集。由于在网上未找到一键标注且生成热力图的工具由此决定自己来写一个这样的小程序。
开发环境:vs2019 ,OpenCV4.4
一、开发流程
思路:采用C++的io处理库获取文件夹下的所有图片名称,之后使用OpenCV读取这些文件名对应的图片,使用OpenCV鼠标处理事件,通过回调函数来记录鼠标的坐标,并且生成热力图。并用C++文件流将坐标写入文件。
二、开发步骤
1.引入头文件
代码如下(示例):
#include<iostream>
#include<opencv2/opencv.hpp>
#include<io.h>
#include<vector>
#include<cmath>
#include <windows.h>
#include <fstream>
2.定义读取目录文件名函数
代码如下(示例):
void getFiles(std::string path,std::vector<std::string>& files)
{
_finddata_t fileInfo;
std::string p;
p.assign(path);
intptr_t handle = _findfirst((p+"//*.jpg").c_str(), &fileInfo);
do
{
std::string name = p + fileInfo.name;
//std::cout << name<< std::endl;
files.push_back(name);
} while (_findnext(handle, &fileInfo) == 0);
_findclose(handle);
}
_finddata_t这个结构体存储了文件名,通过_findfirst寻找文件。
3.定义保存文件和图片函数
void saveMat(cv::Mat &img1)
{
std::string folderPath = "存储路径";
std::string png = "jpg";
folderPath = folderPath + std::to_string(num);
folderPath.push_back('_');
folderPath = folderPath + std::to_string(n);
folderPath.push_back('.');
folderPath = folderPath + png;
cv::imwrite(folderPath, img1);
std::cout <<folderPath<< std::endl;
n++;
}
void writefile(int a, int b)
{
std::ofstream outfile;
outfile.open("存储路径", std::ios::out | std::ios::app);
outfile <<num<<" "<<n<<"("<<a<<","<<b<<")"<< std::endl;
outfile.close();
}
4.定义鼠标回调函数
void MouseEvent(int event, int x, int y, int flags, void* data)
{
if (event == cv::EVENT_LBUTTONDOWN)
{
cv::Mat hm = img;
double x1 = x, y1 = y;
circle(img, cv::Point(x, y), 1, cv::Scalar(0, 0, 255));
cv::cvtColor(hm, hm, cv::COLOR_RGB2GRAY);
cv::Mat M(hm.rows, hm.cols, CV_64FC1, cv::Scalar(0, 0, 255));
for (auto i = 0; i < hm.rows; i++)/*生成热力图*/
{
for (auto j = 0; j < hm.cols; j++)
{
double a1 = i, b1 = j;
double u = (a1-x1)*(a1-x1)+(b1-y1)*(b1-y1);
u = -u / 2 / v / v;
double e = std::exp(u);
M.at<double>(i, j) = e*100;
/*std::cout << u << "******" << e;
return;*/
}
}
saveMat(M);
writefile(x, y);
}
}
5.主函数
std::vector<std::string>filename;
std::string imgpath = "图片路径";
getFiles(imgpath, filename);
for (auto i : filename)
{
std::cout << i << std::endl;
std::cout << num << std::endl;
img = cv::imread(i);
cv::resize(img, img, cv::Size(1008,756));
cv::namedWindow("img");
cv::imshow("img", img);
cv::setMouseCallback("img", MouseEvent);
while (1)
{ if (cv::waitKey(0) == 27)
break;
}
cv::destroyAllWindows();
num++;
n = 0;
}
总结
以上代码可以实现一键关键点坐标保存和热力图生成,既是点击图片上的一点直接保存坐标和生成热力图。
*
注意:由于C++中OpenCV的像素类型为uchar即为8u1c,如果直接让热力图等于0-1之间的一个概率C++直接默认小数等于0,所以在生成热力图时将热力图每个像素扩大了100倍。 不足:之所以没有使用python编程是因为python中OpenCV在读取和保存图像时直接将小数点后舍去了,如何让OpenCV读取小数并且不进行舍入目前没有办法解决,有一个想法是把每个热力图的像素存在文件中之后在进行网络训练时由文件读取到numpy数组里面,但是如果那样工作量就太大了因此放弃。第二个不足之处在于opencv默认的像素的xy轴与我们一般认为的xy轴不太一样,是直接使用了像素坐标系的表示,因此在标注时的关键点位置与热力图位置看起来不一样,不过没关系因为像素坐标在坐标系的位置其实是一样。
标签:std,folderPath,一键,力图,像素,OpenCV,关键点,cv,标注 来源: https://blog.csdn.net/qq_36154011/article/details/114751854