static void on_draw(int event, int x, int y, int flags, void* userobj)
{
Mat image = *(Mat*)userobj;
if (event == EVENT_LBUTTONDOWN) {
//鼠标点击时
sp.x = x;
sp.y = y;
std::cout << "start:" << sp << std::endl;
}
if (event == EVENT_LBUTTONUP) {
//鼠标抬起后
ap.x = x;
ap.y = y;
int dx = ap.x - sp.x;
int dy = ap.y - sp.y;
if (dx > 0 && dy > 0) {
Rect box(sp.x, sp.y, dx, dy);
//绘制矩形
rectangle(image, box, Scalar(0,0,255), 1, 8, 0);
imshow("绘制后", image);
}
std::cout << "end:" << sp << std::endl;
}
}
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("绘制前", WINDOW_AUTOSIZE);
imshow("绘制前", image);
//设置回调机制
setMouseCallback("绘制前",on_draw, (void*)(&image));
}
一个屏幕上只绘制一张图像,当鼠标移动的时候自动清空屏幕
Point sp(-1, -1);
Point ap(-1, -1);
Mat tmp;
static void on_draw(int event, int x, int y,int flags, void* userobj)
{
Mat image = *(Mat*)userobj;
if (event == EVENT_LBUTTONDOWN) {
sp.x = x;
sp.y = y;
std::cout << "start: " << sp << std::endl;
}
//鼠标松开时确定结尾位置,并绘制矩形
else if (event == EVENT_LBUTTONUP) {
ap.x = x;
ap.y = y;
int dx = ap.x - sp.x;
int dy = ap.y - sp.y;
if (sp.x > 0 && sp.y > 0) {
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
imshow("绘制前", image);
//绘制完清空
sp.x = -1;
sp.y = -1;
}
std::cout << "end: " << ap << std::endl;
}
//当鼠标移动的时候会清空屏幕
else if (event == EVENT_MOUSEMOVE) {
tmp.copyTo(image); //清除屏幕
}
}
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("绘制前", WINDOW_AUTOSIZE);
imshow("绘制前", image);
//设置回调机制
setMouseCallback("绘制前",on_draw,(void *)(&image));
tmp = image.clone();
}
提取图像框选中部分
Point sp(-1, -1);
Point ap(-1, -1);
Mat tmp;
static void on_draw(int event, int x, int y,int flags, void* userobj)
{
Mat image = *(Mat*)userobj;
if (event == EVENT_LBUTTONDOWN) {
sp.x = x;
sp.y = y;
std::cout << "start: " << sp << std::endl;
}
//鼠标松开时确定结尾位置,并绘制矩形
else if (event == EVENT_LBUTTONUP) {
ap.x = x;
ap.y = y;
int dx = ap.x - sp.x;
int dy = ap.y - sp.y;
if (sp.x > 0 && sp.y > 0) { //防止越界访问
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
imshow("绘制前", image);
if (dx > 0 && dy > 0) { //防止越界访问
tmp.copyTo(image); //清楚红边框
imshow("ROT截取", image(box));
}
sp.x = -1;
sp.y = -1;
std::cout << "end: " << ap << std::endl;
}
}
//当鼠标移动的时候会清空屏幕
else if (event == EVENT_MOUSEMOVE) {
tmp.copyTo(image); //清除屏幕
}
}
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("绘制前", WINDOW_AUTOSIZE);
imshow("绘制前", image);
//设置回调机制
setMouseCallback("绘制前",on_draw,(void *)(&image));
tmp = image.clone();
}
展示效果:
绘制圆形
Point p(-1, -1);
Mat tmp;
static void on_draw(int event, int x, int y ,int flags, void *userobj)
{
Mat image = *(Mat*)userobj;
if (event == EVENT_LBUTTONDOWN) {
p.x = x;
p.y = y;
std::cout << "start: " << p << std::endl;
}
else if (event == EVENT_LBUTTONUP) {
circle(image, p, 80, Scalar(0,0,255), -1);
imshow("绘制前", image);
}
else if(event == EVENT_MOUSEMOVE){
tmp.copyTo(image); //清空屏幕
}
}
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("绘制前", WINDOW_AUTOSIZE);
imshow("绘制前", image);
//设置回调机制
setMouseCallback("绘制前",on_draw,(void *)(&image));
tmp = image.clone();
}
鼠标点击某一个点会自动画一个圆形
注:最常用的是NORM_MINMAX归一化方法
void normalize(
InputArray src, //输入图像
OutputArray dst, //输出图像
double alpha = 1, //NORM_MINMAX时候最低值
double beta = 0, //NORM_MINMAX时候最高值
int norm_type = NORM_L2, //只有alpha
int dtype = -1, //默认类型与src一致
InputArray mask = noArray() //mask默认值为空
)
void QuickDemo::norm_demo(Mat& image)
{
Mat dst; //存储转换后的结果
std::cout << image.type() << std::endl; //CV_8UC3
image.convertTo(dst, CV_32FC3);
std::cout << dst.type() << std::endl; //CV_32FC3
}
使用normalize函数做归一化处理需要先将CV_8UC3字节类型的图像像素转换为浮点型处理, 因为归一化处理之后的数据范围都在[0, 1]之间,需要用到浮点数保存
void QuickDemo::norm_demo(Mat& image)
{
Mat dst; //存储转换后的结果
std::cout << image.type() << std::endl; //CV_8UC3
image.convertTo(image, CV_32FC3);
std::cout << image.type() << std::endl; //CV_32FC3
normalize(image, dst, 1.0, 0,NORM_MINMAX); //做归一化处理
std::cout << dst.type() << std::endl;
imshow("类型转换CV_32FC3之后", image);
imshow("归一化处理之后", dst);
}
将CV_8UC3类型的数据转换成CV_32FC3数据类型后,可以看出图像的像素类型变了之后,与之前的差异比较大,可是做完归一化处理之后在肉眼观察基本上跟原图没有啥区别。
void QuickDemo::resize_demo(Mat& image)
{
Mat zoomin, zoomout; //放大缩小对象
int h = image.rows; //行
int w = image.cols; //列
//按照宽高进行缩小
resize(image, zoomout, Size(h / 2, w / 2));
imshow("缩小", zoomout);
//按照宽高进行放大
resize(image, zoomin, Size(h * 1.5, w * 1.5));
imshow("放大", zoomin);
}
鼠标滚动事件缩小和放大窗口
原理
其中scale可以在外部定义为全局变量,通过响应CV_EVENT_MOUSEWHEEL滑轮事件获取Scale的具体值。
获取Scale值需要关注两个问题,滑轮滑动的方向和滑动量的大小。滑动方向通过getMouseWheelDelta(flags)获取,
当返回值>0时,表示向前滑动;
当返回值<0时,表示向后滑动。滑动量根据滑动方向自行设置相应的滑动步长即可。
void call_back(int event, int x, int y, int flags, void*userobj)
{
Mat src = *(Mat*)userobj;
Mat zoominout;
int h = src.rows;
int w = src.cols;
//获取滚动事件
if (event == cv::EVENT_MOUSEWHEEL) {
//获取鼠标上下滚动时的值
int Scale = getMouseWheelDelta(flags);
if (Scale > 0) {
Scale = Scale / 120 + 1.5; //放大1.5倍
resize(src, zoominout, Size(h * Scale, w * Scale), INTER_LINEAR);
}
if (Scale < 0) {
Scale = abs(Scale / 120) + 1; //缩小2倍
resize(src, zoominout, Size(h / Scale, w / Scale), INTER_LINEAR);
}
imshow("触发后", zoominout);
}
}
void QuickDemo::mouse_resize_demo(Mat& image)
{
namedWindow("鼠标触发事件", WINDOW_AUTOSIZE);
setMouseCallback("鼠标触发事件", call_back, (void *)(&image));
imshow("鼠标触发事件", image);
}
将鼠标悬浮在鼠标触发事件窗口上,可以使用鼠标的滚轮进行放大和缩小
createTrackbar 创建滚动条的方式调整图片大小
Mat dst, m, src;
void on_track1(int val, void *userobj)
{
int h = src.rows;
int w = src.cols;
resize(src, dst, Size(h + val, w + val), INTER_LINEAR);
imshow("调整后", dst);
}
void QuickDemo::mycreateTrackbar(Mat& image) {
int val = 50;
dst = Mat::zeros(image.size(), image.type());
m = Mat::zeros(image.size(), image.type());
src = image.clone(); //深拷贝
namedWindow("调整", WINDOW_AUTOSIZE);
//当滚动按钮被拖动的时候,on_track函数会去调整光的亮度
createTrackbar("调整", "调整", &val,
200, on_track1, (void *)&image);
on_track1(50, 0); //固定写法
imshow("调整", image);
}