起因:最近对图片进行截取矩形区域操作时,发现了opencv一个很蛋痛的地方,使用imshow()函数展示图片的时候,一旦图片的分辨率过高,就不能完全显示。要是调整参数为WINDOWSIZE_NORMAL的话,截取出来的矩形区域和原图并不是一一对应的。使用resize函数的话,先缩小在放大又会使图片变得异常模糊。只好上网查了一下给图片加上滑动条的文章,然而只找到了opecv2写的函数,现用opencv4重写如下。
目的:给分辨率过大的图片加上滑动条。
原理:截取原图中符合窗口大小的部分并在窗口中显示
代码:
#include<opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int h_x=0, v_y=0,d_x=0,d_y=0; //记录滑动条变化值,以及保存当前值
Rect v_bar, h_bar;
Point start; //移动鼠标时的基点,使用了全局变量以使得滑动条的位置可以被记录下来。也可设为局部的静态变量
bool x_change = false;
bool y_change = false; //判断是否改变
void on_mouse(int event, int x, int y, int flags, void* param);
void draw_scrolls(Mat src_img, const char* title, int width = 500, int height = 700); //后两个参数设置窗口的默认大小
int main()
{
const char* title = "source";
Mat srcimg = imread("E:\\material\\shaoyun.jpg");
namedWindow(title, 1);
setMouseCallback(title, on_mouse);
while (true)
{
char c = waitKey(10);
draw_scrolls(srcimg,title);
if (c == ' ')
break;
}
}
void draw_scrolls(Mat src_img, const char* title, int width, int height)
{
Mat temp_img, src_rect, temp_rect;
Mat src_roi;
Rect v_rect,h_rect;
int img_width, img_height; //img的width和height
int win_width, win_height; //window的width和height
int show_width, show_height; //窗口中图片的width和height
int bar_width=25; //滑动条的宽度
double scale_h, scale_w; //img和window的width,height之比
int img_y=0,img_x=0; //上下滑动后截取图片左上顶点的y值,左右滑动后截取图片左上角x值
img_width = src_img.cols;
img_height = src_img.rows;
win_width=show_width = min(img_width,width);
win_height=show_height = min(img_height,height);
scale_h = (double)img_height / height;
scale_w = (double)img_width / width;
//高度过高需要加竖直滑动
if (scale_h>1)
{
win_width = img_width > width ? width + bar_width : img_width + bar_width;
show_width = win_width - bar_width;
}
//宽度过宽需要加水平滑动
if (scale_w>1)
{
win_height = img_height > height ? height + bar_width : img_height + bar_width;
show_height = win_height - bar_width;
}
temp_img = Mat::zeros(Size(win_width, win_height), CV_8UC3);
if (scale_h > 1)
{
v_y += d_y;
d_y = 0;
v_y = v_y < 0 ? 0 : (v_y > (int)((1 - 1 / scale_h) * win_height) ? (int)((1 - 1 / scale_h) * win_height) : v_y);
img_y = (int)(v_y * img_height / win_height);//img_y = (int)(v_y / ((1-1/scale_h) * win_height) * (1 - 1 / scale_h)*img_height)的简化
v_rect = Rect(show_width + 1, 0, bar_width, win_height); //竖直滑动条底层
v_bar = Rect(show_width + 1, v_y, bar_width, (int)((double)win_height / scale_h)); //竖直滑动条
rectangle(temp_img, v_rect, Scalar::all(0), -1);
rectangle(temp_img, v_bar, Scalar::all(255), -1);
}
if (scale_w > 1)
{
h_x+=d_x;
d_x = 0;
h_x = h_x < 0 ? 0 : (h_x > (int)((1 - 1 / scale_w) * win_width) ? (int)((1 - 1 / scale_w) * win_width) : h_x);
img_x = (int)(h_x * img_width / win_width); //同上
h_rect = Rect(0, show_height + 1, win_width, bar_width); //水平滑动条底层
h_bar = Rect(h_x, show_height + 1, (int)((double)win_width / scale_w), bar_width); //水平滑动条
rectangle(temp_img, h_rect, Scalar::all(0), -1);
rectangle(temp_img, h_bar, Scalar::all(255), -1);
}
temp_rect = temp_img(Rect(0, 0, show_width, show_height)); //窗口显示图片部分
src_rect = src_img(Rect(img_x, img_y, show_width, show_height)); //原图截取部分
src_rect.copyTo(temp_rect);
imshow(title, temp_img);
}
void on_mouse(int event, int x, int y, int flags, void* param)
{
Point curse = Point(x, y);
Point now;
//点击竖直滑动条
if (v_bar.contains(curse))
{
if (event == EVENT_LBUTTONDOWN)
{
start = Point(x, y);
y_change = true;
}
}
//点击水平滑动条
if (h_bar.contains(curse))
{
if (event == EVENT_LBUTTONDOWN)
{
start = Point(x, y);
x_change = true;
}
}
//拖动
if (event == EVENT_MOUSEMOVE)
{
now = Point(x, y);
if (y_change)
{
d_y = now.y - start.y;
start = now;
}
if (x_change)
{
d_x = now.x - start.x;
start = now;
}
}
if (event == EVENT_LBUTTONUP)
{
x_change = y_change = false;
}
}
原图:
效果图:
————————————————
版权声明:本文为CSDN博主「三更打雨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Dr_maker/article/details/100833890