学习需要总结和交流。最近在做深度学习方面的工作,需要写一个标记小程序。编程期间参考了很多blog,终于完成了这个程序。想通过我的第一篇blog分享出去,和大家多多交流,同时自己也总结一下收获。好了,下面正式开始。
编程之前,我的目的是要实现一个能够根据键盘按键来标记图片上不同点的程序,同时能够方便地保存以及切换到下一张图片。
我想到的第一个问题是如何读取键盘按键,有两个方法:
1、opencv中waitKey()函数
2、C++的cin,getchar,getline等。
考虑到需要边读取键盘按键,边标记程序,起初我想通过pthread创建子线程来读取键盘按键。利用第二种读取方法读键值,遇到问题:linux的终端在opencv窗口后面,需要切换窗口还有输入结束符号,麻烦,放弃。这种情况下使用waitKey()函数发现waitKey需要显示一个opencv窗口才可以,也放弃了。
最终我的实现方案:主程序利用while循环waitKey函数读取键盘按键,利用opencv窗口函数实现图片标记。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <sys/types.h>
#define WINDOW_NAME "PICTURE"
#define RED 1
#define GREEN 2
#define BLUE 3
#define ERASER 999
using namespace std;
using namespace cv;
Point point;
bool g_bDrawingBox = false;
bool g_button = false;
bool next = true;
int CurColor;
int colValue = 0;
int curKey;
int colorR = 0;
int imgNum = 0;
Mat resImage;
Mat srcImage;
Mat tempImage;
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawPoint( cv::Mat& img, cv::Point point,int color );
void SetGreyValue(cv::Mat& img, cv::Point point,int color );
vector<Mat> read_images_in_folder(cv::String pattern);
int main()
{
bool curSaveFlag = false;
//遍历文件夹搜寻图片
cv::String pattern = "/home/lwh/Project/MarkChip/build/chipimg/*.bmp";
cv::String savedirstr = "/home/lwh/Project/MarkChip/build/chipimg_label/";
//linux系统函数mkdir函数创建标记后的图片
if(0 == mkdir( savedirstr.c_str(),S_IRWXU))
{
cout <<"Create dir successfully!" <<endl;
}
else
{
cout <<"Can't create dir!" <<endl;
}
cv::String curImgName;
vector<cv::String> fn;
glob(pattern, fn, false);
size_t count = fn.size(); //number of png files in images folder
//设置鼠标操作回调函数
while(1)
{
if(next)
{
srcImage = imread(fn[imgNum]);
srcImage.copyTo(tempImage);
resImage = Mat::zeros(srcImage.size(),CV_8UC1);
size_t bmppos = fn[imgNum].find("chipimg");
curImgName = fn[imgNum].substr(bmppos + 8,1000);
cout << curImgName <<endl;
namedWindow( WINDOW_NAME );
imshow(WINDOW_NAME,tempImage);
setMouseCallback(WINDOW_NAME,on_MouseHandle,(void*)&tempImage);
next = false;
}
curKey = waitKey(10);
switch(curKey)
{
case 122://z
case 90://Z
{
CurColor = RED;
colValue = 1;
g_button = true;
}
break;
case 120://x
case 88://X
{
CurColor = GREEN;
colValue = 2;
g_button = true;
}
break;
case 99://c
case 67://C
{
CurColor = BLUE;
colValue = 3;
g_button = true;
}
break;
case 118://v
case 86://V
{
CurColor = 3;
colValue = 0;
g_button = true;
}
break;
case 81:
case 113:
{
CurColor = ERASER;
g_button = true;
}
break;
//调整画笔大小
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
case 58:
{
colorR = curKey-48;
cout << "The current pencil radius:"<< colorR<< endl;
}
break;
//S键,save
case 115:
{
cv::String filename = savedirstr + curImgName;
try
{
imwrite(filename,resImage);
}catch(runtime_error& ex)
{
cout<< "Can't save picture "<< imgNum << ex.what() << endl;
}
curSaveFlag = true;
cout<< "Save picture "<< imgNum << ":"<< filename <<" successfully!" << endl;
}
break;
//->和\|/键,下一张
//case 83:
case 100:
{
if(!curSaveFlag)
{
cout << "WARNNING! The current image hasn't been saved!"<< endl;
}else
{
imgNum++;
cout << "The current image number is :" << imgNum << endl;
curSaveFlag = false;
next = true;
resImage.release();
srcImage.release();
tempImage.release();
destroyWindow(WINDOW_NAME) ;
}
}
break;
default:
{
CurColor = 0;
g_button = false;
break;
}
}
if( curKey == 27 ) break;//按下ESC键,程序退出
}
return 0;
}
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
Mat& image = *(cv::Mat*) param;
switch( event)
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if( g_button )
{
g_bDrawingBox = true;
point.x = x;
point.y = y;
DrawPoint(image, point,CurColor);
SetGreyValue(resImage, point,CurColor );
//resImage.at<uchar>(y,x) = 250;
}
}
break;
//左键按下消息
case EVENT_LBUTTONDOWN:
{
if(g_button)
{
g_bDrawingBox = true;
SetGreyValue(resImage, point,CurColor );
}
}
break;
//左键抬起消息
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;
g_button = false;
}
break;
}
}
void SetGreyValue(cv::Mat& img, cv::Point point,int color )
{
switch(color)
{
case RED:
{
img.at<uchar>(point) = 250;
}
break;
case GREEN:
{
img.at<uchar>(point) = 128;
}
break;
case BLUE:
{
img.at<uchar>(point) = 64;
}
break;
//清除某一点
case ERASER:
{
cv::circle(img,point,0,0,-1);
}
break;
default:
cv::circle(img,point,colorR,cv::Scalar(0,0,255),-1);
break;
}
}
void DrawPoint( cv::Mat& img, cv::Point point,int color )
//cvScaler::BGR
{
switch(color)
{
case RED:
{
cv::circle(img,point,colorR,cv::Scalar(0,0,255),-1);
}
break;
case GREEN:
{
cv::circle(img,point,colorR,cv::Scalar(0,255,0),-1);
}
break;
case BLUE:
{
cv::circle(img,point,colorR,cv::Scalar(255,0,0),-1);
}
break;
//清除某一点
case ERASER:
{
cv::circle(img,point,0,srcImage.at<Vec3b>(point),-1);
for(int i =-colorR;i<colorR;i++)
{
for(int j =-colorR;j<colorR;j++)
{
Point tempoint= Point(point.x+i,point.y+j);
cv::circle(img,tempoint,0,srcImage.at<Vec3b>(tempoint),-1);
}
}
}
break;
default:
cv::circle(img,point,colorR,cv::Scalar(0,0,255),-1);
break;
}
//图像融合显示
//IplImage IMG;
// addWeighted(IplImage(srcImage),0.5,IplImage(img),0.5,IMG);
Mat IMG;
addWeighted(srcImage,0.8,img,0.2,0,IMG);
imshow( WINDOW_NAME, IMG );
}