图像加载与显示
读取图像 imread() 返回一个 **Mat **对象;
展示图像 imshow();
waitKey(int num)
;num = 0
表示等待(阻塞),num > 0
停顿num毫秒;cv::namedWindow("窗口名");
: 有其他重载和参数:如下cv::imread("图片路径",flag);
:第二个参数是一个 flag,指定了应该读取图像的方式;( 只支持8位或浮点数类显示,其它类型有点问题 ) 例子如下代码;- IMREAD_COLOR:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志
- IMREAD_GRAYSCALE:以灰度模式加载图像
- IMREAD_UNCHANGED:加载图像,包括 alpha (透明)通道
- ``
#include <iostream>
#include "opencv2/opencv.hpp"
int main() {
//cv::IMREAD_GRAYSCALE 图片显示为灰色
cv::Mat img = cv::imread("cfy.jpg",cv::IMREAD_GRAYSCALE);
//cv::WINDOW_FREERATIO 可以调整窗口大小
cv::namedWindow("img",cv::WINDOW_FREERATIO);
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
img.depth()
:返回各个图片深度代表的枚举值img.empty()
:是否为空白
以上img均为cv::Mat 类型
图像色彩空间转换
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
色彩空间转换函数;函数参数解释:
- src(source):输入的源图像。为矩阵形式。
- dst(destination):输出的目标图像,即经过色彩转后我们需要得到的图像。也为矩阵形式。
- code:颜色空间转换的标识符,表示我们所要进行空间转换的结果。
code的参数多达200多,在此列举一些常用的参数,更多参数请查阅opencv官方文档
空间转换 | 标识符 | code |
---|---|---|
BGR——灰度 | COLOR_BGR2GRAY | 6 |
RGB——灰度 | COLOR_RGB2GRAY | 7 |
灰度——RGB/BGR | COLOR_GRAY2RGB = COLOR_GRAY2BGR | 8 |
BGR——HSV | COLOR_BGR2HSV | 40 |
RGB——HSV | COLOR_RGB2HSV | 41 |
HSV——BGR | COLOR_HSV2BGR | 54 |
HSV——RGB | COLOR_HSV2RGB | 55 |
- 注意!此处有知识点!在opencv中彩色图像(RGB图像)按照BGR顺序进行存储。所以以彩色图像为源图像进行颜色空间转换时,注意是“BGR2”。
- dstCn:目标图像的通道数。默认值为0,表示目标图像取源图像的通道数 。
void QuickDemo::colorSpace_Demo(Mat &image)
{
Mat gray, hsv;
cvtColor(image,hsv,COLOR_RGB2HSV);
cvtColor(image, gray, COLOR_BGR2GRAY);
imshow("HSV",hsv);
imshow("灰度", gray);
imwrite("B:/c++/opencv_object/opencv1/save_img/hsv.png",hsv);
imwrite("B:/c++/opencv_object/opencv1/save_img/gray.png", gray);
}
摘自:初学opencv c++学习笔记(二)图像空间色彩转换cvtColor()
图像对象的创建与赋值
创建空白mat
Mat m3 = Mat::zeros(Size(8,8),CV_8UC3);
std::cout << "width: " << m3.cols << " height: " << m3.rows << std::endl;
std::cout<<" channels(通道数): " << m3.channels() << std::endl;
std::cout << m3 << std::endl;
- 参数:CV_8UC3
通道数为:3; 结果:每个像素点占三个数据,则一行宽度为像素宽度 * 通道数
;- 还可以利用
Mat m3 = Mat::ones(Size(8,8),CV_8UC1);
初始化各个像素点为1;如果使用3通道则会造成只初始化一个通道如图:
赋值
- 可以直接赋值但是只会赋值第一个通道
Mat m3 = Mat::zeros(Size(8,8),CV_8UC3);
m3 = 127;
- 在知道通道数时,利用
m3 = Scalar(123,111,211);
赋值;
void QuickDemo::mat_creation_Demo(Mat& image)
{
//创建空白
Mat m3 = Mat::zeros(Size(400,400),CV_8UC3);
m3 = Scalar(123,111,211);//赋值最大为255
imshow("图像", m3);
}
- 还可以
Mat m4 = m3;
但只拷贝了矩阵头部,共用一块数据;
Mat m3 = Mat::zeros(Size(400,400),CV_8UC3);
m3 = Scalar(255,0,255);//赋值最大为255
//imshow("图像", m3);
Mat m4 = m3;
m4 = Scalar(0,255,255);
imshow("图像", m3);
std::cout << m3 << std::endl;
复制 与 克隆
- 利用复制 和克隆会产生一个新的数据部分与原来不发生关系
void QuickDemo::mat_creation_Demo(Mat& image)
{
Mat m1, m2;
//克隆
m1 = image.clone();
//拷贝
image.copyTo(m2);
}
图像像素的读写操作
- Vec3b存储3通道像素对象
基于数组下标
void QuickDemo::pixel_visit_Demo(Mat& image)
{
int width = image.cols;
int hight = image.rows;
//通道数
int dims = image.channels();
for (int row = 0; row < hight; row++) {
for (int col = 0; col <width; col++) {
if (dims == 1) {
//单通道像素点(灰度图像)
int pv = image.at<uchar>(row,col);
image.at<uchar>(row, col) = 255 - pv;
}
if(dims==3){
//彩色图像(三通道)
Vec3b bgr = image.at<Vec3b>(row, col);
image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
imshow("读写展示",image);
}
基于指针
- 速度更快
void QuickDemo::pixel_visit_Demo(Mat& image)
{
int width = image.cols;
int hight = image.rows;
//通道数
int dims = image.channels();
for (int row = 0; row < hight; row++) {
uchar* current_row = image.ptr<uchar>(row);
for (int col = 0; col <width; col++) {
if (dims == 1) {
//单通道像素点(灰度图像)
int pv = *current_row;
*current_row++ = 255 - pv;
}
if(dims==3){
//彩色图像(三通道)
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
imshow("读写展示",image);
}
图像像素基本操作
- 加减除均可以
void QuickDemo::operators_Demo(Mat& image)
{
Mat m;
m = image + Scalar(20,20,20);
imshow("加法操作",m);
}
- 乘法
void QuickDemo::operators_Demo(Mat& image)
{
Mat result;
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(2, 2, 2);
multiply(image, m, result);
imshow("乘法操作",result);
}
saturate_cast<uchar>
主要是为了防止颜色溢出操作;详解
void QuickDemo::operators_Demo(Mat& image)
{
Mat result = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(2, 2, 2);
multiply(image, m, result);
imshow("乘法操作",result);
int width = image.cols;
int hight = image.rows;
//通道数
int dims = image.channels();
for (int row = 0; row < hight; row++) {
for (int col = 0; col < width; col++) {
Vec3b p1 = image.at<Vec3b>(row, col);
Vec3b p2 = m.at<Vec3b>(row, col);
result.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
result.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
result.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
}
}
imshow("读写展示", image);
}
api函数
add
加法subtract
减法divide
除法multiply
乘法
滚动条操作
调整图像亮度
- 以下:
createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track);
利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
Mat dst, m, src;
//当前亮度(进度条当前值)
int lightness = 50;
static void on_track(int, void*) {
m = Scalar(lightness,lightness,lightness);
add(src,m,dst);
imshow("亮度调整",dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
dst = Mat::zeros(image.size(), image.type());
m = Mat::zeros(image.size(), image.type());
src = image;
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int max_value = 100;
//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
//类似于信号与槽
createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track);
//当前没用
on_track(50,0);
}
参数传递、亮度、对比度
- 函数指针
- static在修饰局部变量和函数的作用
- userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
- value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
//opencv源代码函数指针
typedef void (*TrackbarCallback)(int pos, void* userdata);
//opencv源代码函数声明
CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,int* value, int count,TrackbarCallback onChange = 0,void* userdata = 0);
void* userdata
无类型指针传递参数
static void on_track(int pos, void* userdata ) {
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(pos,pos,pos);
add(image,m,dst);
imshow("亮度调整",dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int max_value = 100;
//当前亮度(进度条当前值)
int lightness = 50;
//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
//类似于信号与槽
//userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
//value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track,(void*)&image);
//on_track(50,&image); 可以省略
}
- 亮度与对比度
- 注意: createTrackbar函数窗口名字必须有创建指定否则会出现空指针;imshow的窗口名称如果已有则用已有,否则创建新的窗口,如下两个滚动条改变都展现在“亮度调整”窗口
- addWeighted()
static void on_lightness(int pos, void* userdata) {
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
//add(image, m, dst);
addWeighted(image, 1.0, m, 0, pos, dst);
imshow("亮度调整", dst);
}
static void on_contrast(int pos, void* userdata) {
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
//第一个的权重 通过进度条来改变
double contrast = pos / 100.0;
addWeighted(image,contrast, m,0.0,0, dst);
imshow("亮度调整", dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int max_value = 100;
//当前亮度(进度条当前值)
int lightness = 50;
int contrast = 100;
//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
//类似于信号与槽
//userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
//value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
createTrackbar("value bar:", "亮度调整", &lightness, max_value, on_lightness,(void*)&image);
createTrackbar("Contrast bar:", "亮度调整", &contrast, 200 , on_contrast,&image);
on_lightness(50,&image);
}
键盘响应操作
char c = cv::waitKey(时间);
在等待时间按键返回按键键值;
void QuickDemo::key_Demo(Mat& image)
{
Mat dst = Mat::zeros(image.size(),image.type());
//使用英文输入法
while (true) {
//等待输入
int c = waitKey(0);
if (c == 27) {
std::cout << "key = Esc" << std::endl;
break;
}
if (c == 49) {
std::cout << "key = 1" << std::endl;
cvtColor(image, dst, COLOR_BGR2GRAY);
}
if (c == 50) {
std::cout << "key = 2" << std::endl;
cvtColor(image, dst, COLOR_BGR2HSV);
}
if (c == 51) {
std::cout << "key = 3" << std::endl;
dst = Scalar(50, 50, 50);
add(image, dst, dst);
}
imshow("键盘响应", dst);
}
}
opencv自带颜色表操作
- 源函数
void applyColorMap(InputArray src, OutputArray dst, int colormap);
- 代码
void QuickDemo::color_style_demo(Mat& image) {
//颜色表数组
int colormap[] = {COLORMAP_AUTUMN,COLORMAP_BONE,COLORMAP_JET,COLORMAP_WINTER,
COLORMAP_RAINBOW,COLORMAP_OCEAN,COLORMAP_SUMMER,COLORMAP_SPRING,
COLORMAP_COOL,COLORMAP_HSV,COLORMAP_PINK,COLORMAP_HOT,
COLORMAP_PARULA,COLORMAP_MAGMA,COLORMAP_INFERNO,COLORMAP_PLASMA,
COLORMAP_VIRIDIS,COLORMAP_CIVIDIS,COLORMAP_TWILIGHT,COLORMAP_TWILIGHT_SHIFTED,
COLORMAP_TURBO,COLORMAP_DEEPGREEN
};
Mat dst;
int index = 0;
while (true) {
int c = waitKey(500);
if (c == 27) {//key:esc
break;
}
applyColorMap(image, dst, colormap[index % 22]);
//std::cout <<index<<"," << index % 22 << std::endl;
index++;
imshow("颜色风格", dst);
}
}
图像像素的逻辑操作
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
绘制矩形- 位操作
void QuickDemo::bitwise_Demo(Mat& image) {
Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
//第三个参数小于0为填充;大于0为绘制;
//抗锯齿能力:LINE_AA > LINE_8 > LINE_4
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
imshow("m1", m1);
imshow("m2", m2);
Mat dst;
//bitwise_and(m1, m2, dst);//Scalar(0,255,0
//bitwise_or(m1, m2, dst);
bitwise_not(image, dst); // 另一种取反方式:Mat dst = ~image;
//bitwise_xor(m1, m2, dst);
imshow("位操作", dst);
}
通道分离与合并
CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts,const int* fromTo, size_t npairs);
通道换位- mixChannels
void QuickDemo::split_merge_Demo(Mat& image) {
std::vector<Mat>mv;
split(image, mv);
imshow("b", mv[0]);
imshow("g", mv[1]);
imshow("r", mv[2]);
Mat dst;
//三个通道组成各种颜色,如下eg:蓝色通道为0,则为绿色+红色=黄色
mv[0] = 0;
//mv[1] = 0;
//mv待合并矩阵的输入向量;mv中的所有矩阵必须具有相同的大小和相同的深度。
//dst输出与mv[O]相同大小和深度的数组;通道数将是矩阵数组中通道的总数。
merge(mv, dst);
imshow("dst", dst);
//转换数组:两个为一组,第0通道到第2通道(0->2)还有(1->1),(2->0)
int from_to[] = { 0,2,1,1,2,0 };
mixChannels(&image, 1, &dst, 1, from_to, 3);
imshow("通道混合", dst);
}
图像色彩空间转换
void QuickDemo::inrange_Demo(Mat& image) {
Mat hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
Mat mask;
//(35, 43, 46)绿色最小值
/*inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);*/
//将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)
inRange(hsv, Scalar(0, 0, 221), Scalar(180, 30, 255), mask);
//抠出人像黑色区域
//imshow("mask", mask);
//创建空白图像
Mat redback = Mat::zeros(image.size(), image.type());
//设为红色
redback = Scalar(40, 40, 200);
//取反黑白互换 人像位置为黑,其余为白。
bitwise_not(mask, mask);
imshow("mask", mask);
//mask是罩子,把人像通过mask抠出复制到readback
image.copyTo(redback, mask);
imshow("roi", redback);
}
图像像素值统计
- minMaxLoc()用于找到一个多维数组中的最小值和最大值,以及它们的位置。(传入的值必须是单通道的)
- meanStdDev()OpenCV计算图像的平均值和标准差的函数meanStdDev函数的使用
void QuickDemo::pixel_statistic_Demo(Mat& image) {
//最大小值
double minv, maxv;
//最大小值位置
Point minloc, maxloc;
//cvtColor(image, image,COLOR_BGR2GRAY);
std::vector<Mat>mv;
split(image, mv);
for (int i = 0; i < image.channels(); i++) {
minMaxLoc(mv[i], &minv, &maxv, &minloc, &maxloc, Mat());
std::cout << "min value:" << minv << " max value:" << maxv << std::endl;
}
Mat mean, stddev;
meanStdDev(image, mean, stddev);
std::cout << "mead:" << mean << " stddev:" << stddev << std::endl;
}
图像几何形状绘制
cv::Rect
矩形- OpenCV——基本图形绘制(椭圆、圆、多边形、直线、矩形)
- OpenCV画框函数rectangle的使用
circle:
函数原型- img为源图像指针
- center为画圆的圆心坐标
- radius为圆的半径
- color为设定圆的颜色,规则根据B(蓝)G(绿)R(红)
- thickness 如果是正数,表示组成圆的线条的粗细程度。否则,-1表示圆是否被填充
- line_type 线条的类型。默认是8
- shift 圆心坐标点和半径值的小数点位数
cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int lineType=8, int shift=0)
- 绘制结果:
void QuickDemo::drawing_demo(Mat& image) {
//定义矩形
Rect rect;
rect.x = 100;
rect.y = 100;
rect.width = 50;
rect.height = 50;
//绘制矩形
rectangle(image, rect, Scalar(0, 0, 255), -1, 8, 0);
//绘制圆
circle(image, Point(50, 50), 45, Scalar(0, 255, 0), 1, 8, 0);
//绘制线
line(image, Point(50, 50), Point(100, 100), Scalar(0, 255, 0), 2, 8, 0);
//椭圆
RotatedRect rrt;
rrt.center = Point(100, 100);
rrt.size = Size(100, 50);
rrt.angle = 0.0;
//绘制椭圆
//ellipse(image, rrt, Scalar(255, 255, 0), 2, 8);
Mat bg = Mat::zeros(image.size(), image.type());
Mat dst;
//绘制为类似于遮盖的图片 结果图如上述图片‘绘制图形’
circle(bg, Point(100, 200), 100, Scalar(255, 0, 0), -1, 8, 0);
addWeighted(image, 0.7, bg, 0.3, 0, dst);
imshow("绘制演示", dst);
}
随机数与随机颜色
void QuickDemo::random_drawing() {
//创建画布
Mat bg = Mat::zeros(Size(600, 600), CV_8UC3);
int w = bg.cols;
int h = bg.rows;
//产生随机数
RNG rng(12345);
while (true) {
int c = waitKey(1000);
if (c == 27) {
break;
}
//产生一个{rng.uniform(a, b);}a和b之间的随机数
int x1 = rng.uniform(0, w);
int y1 = rng.uniform(0, h);
int x2 = rng.uniform(0, w);
int y2 = rng.uniform(0, h);
int b = rng.uniform(0, 255);
int g = rng.uniform(0, 255);
int r = rng.uniform(0, 255);
bg = Scalar(0, 0, 0);
line(bg, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 2, 8, 0);
imshow("随机绘制", bg);
}
}
多边形填充与绘制
void QuickDemo::polyline_drawing_demo() {
Mat bg = Mat::zeros(Size(512, 512), CV_8UC3);
Point p1(100, 100);
Point p2(350, 100);
Point p3(400, 280);
Point p4(320, 480);
Point p5(80, 400);
std::vector<Point> pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
//在图像上绘制带填充效果的多边形。
//fillPoly(bg, pts, Scalar(255, 0, 0), 8, 0);
// 绘制多边形,不能进行填充
//polylines(bg, pts, true, Scalar(0, 0, 255), 2, LINE_AA, 0);
std::vector<std::vector<Point>> cnts;
cnts.push_back(pts);
drawContours(bg, cnts, -1, Scalar(0, 255, 0), 2);
imshow("多边形绘制", bg);
}
鼠标操作与响应
-
源函数:
CV_EXPORTS void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
-
回调函数格式:
typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
- event 是
CV_EVENT_*
变量之一,CV_EVENT
见下表; - x 和 y 是鼠标在图像坐标系的坐标(不是窗口坐标系);
- flags 是
CV_EVENT_FLAG
的组合; - param 是用户定义的传递到 setMouseCallback 函数调用的参数。
- event 是
-
event 具体说明如下:
枚举值 | 值 | 代表内容 |
---|---|---|
EVENT_MOUSEMOVE | 0 | 滑动 |
EVENT_LBUTTONDOWN | 1 | 左键点击 |
EVENT_RBUTTONDOWN | 2 | 右键点击 |
EVENT_MBUTTONDOWN | 3 | 中键点击 |
EVENT_LBUTTONUP | 4 | 左键放开 |
EVENT_RBUTTONUP | 5 | 右键放开 |
EVENT_MBUTTONUP | 6 | 中键放开 |
EVENT_LBUTTONDBLCLK | 7 | 左键双击 |
EVENT_RBUTTONDBLCLK | 8 | 右键双击 |
EVENT_MBUTTONDBLCLK | 9 | 中键双击 |
- flags 具体说明如下:
枚举值 | 值 | 代表内容 |
---|---|---|
EVENT_FLAG_LBUTTON | 1 | 左键拖曳 |
EVENT_FLAG_RBUTTON | 2 | 右键拖曳 |
EVENT_FLAG_MBUTTON | 4 | 中键拖曳 |
EVENT_FLAG_CTRLKEY | 8 | (8~15)按 Ctrl 不放 |
EVENT_FLAG_SHIFTKEY | 16 | (16~31)按 Shift 不放 |
EVENT_FLAG_ALTKEY | 32 | (32~39)按 Alt 不放 |
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_drawing(int event, int x, int y, int flags, void* userdata) {
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN) {
//按下鼠标位置
sp.x = x;
sp.y = y;
std::cout << "start point:" << sp << std::endl;
}
else if (event == EVENT_LBUTTONUP) {
//抬起鼠标位置
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx >= 0 && dy > 0) {
Rect box(sp.x, sp.y, dx, dy);
temp.copyTo(image);
imshow("截取ROI", image(box));
rectangle(image, box, Scalar(0, 255, 0), 2, 8);
imshow("鼠标绘制", image);
sp.x = -1;
sp.y = -1;
}
}
else if (event == EVENT_MOUSEMOVE) {
if (sp.x > 0 && sp.y > 0) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx >= 0 && dy > 0) {
Rect box(sp.x, sp.y, dx, dy);
temp.copyTo(image);
rectangle(image, box, Scalar(0, 255, 0), 2, 8);
imshow("鼠标绘制", image);
}
}
}
}
void QuickDemo::mouse_drawing_demo(Mat& image) {
namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
//回调函数 类似与信号与槽
setMouseCallback("鼠标绘制", on_drawing, (void*)(&image));
imshow("鼠标绘制", image);
temp = image.clone();
}
图像像素类型转换与归一化
1、函数原型
void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())
2.函数作用
归一化数据。该函数分为范围归一化与数据值归一化。(Normalizes the norm or value range of an array.)
3.参数说明
-
src 输入数组;
-
dst 输出数组,数组的大小和原数组一致;
-
alpha 1,用来规范值,2.规范范围,并且是下限;
-
beta 只用来规范范围并且是上限;
-
norm_type 归一化选择的数学公式类型;
-
dtype 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;
-
mark 掩码。选择感兴趣区域,选定后只能对该区域进行操作。
4.归一化选择的数学公式类型介绍(norm_type)
5.举例说明:
src={10,23,71}
NORM_L1运算后得到 dst={0.096,0.221,0.683}
NORM_INF运算后得到 dst={0.141,0.324,1}
NORM_L2运算后得到 dst={0.133,0.307,0.947}
NORM_MINMAX运算得到 dst={0,0.377,1}
6.范围归一化与值归一化的区别
区别一:范围归一化使用的是如下式子,设范围为【0,255】
即把src缩放到【0,255】这个范围内,并不使用上面的4个公式去解。
区别二:使用范围归一化时,beta必有值不等于0
cv::normalize(a, a, 1,0, cv::NORM_MINMAX);
cv::normalize(a, a, 0,255, cv::NORM_MINMAX);
案例
void QuickDemo::norm_demo(Mat& image) {
Mat dst;
std::cout << image.type() << std::endl;
//转换为浮点防止归一化由于类型转换无法显示后无法显示
image.convertTo(image, CV_32F);
std::cout << image.type() << std::endl;
normalize(image, dst, 1.0, 0, NORM_MINMAX);
std::cout << dst.type() << std::endl;
imshow("图像数据归一化", dst);
}
图像放缩与差值
void QuickDemo::resize_demo(Mat& image) {
Mat zoomin, zoomout;
int h = image.cols;
int w = image.rows;
resize(image, zoomin, Size(w / 1.5, h / 1.5), 0, 0, INTER_LINEAR);
resize(image, zoomout, Size(w * 1.2, h * 1.2), 0, 0, INTER_LINEAR);
imshow("缩小", zoomin);
imshow("放大", zoomout);
}
图像翻转与旋转
图像翻转
void QuickDemo::flip_demo(Mat& image) {
Mat dst;
// 0以x为轴镜像(上下),1以y轴镜像(左右),-1以x=y为轴镜像(相当于旋转180°)
flip(image, dst, 1);
imshow("图像翻转", dst);
}
图像旋转
-
参数列表:
- 旋转中心
- 旋转角度
- 旋转后的缩放比例
-
构造矩阵利用
getRotationMatrix2D()
构造如图:
-
则旋转角度:
double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
M.at<double>(0, 2) += (nw / 2 - w / 2);
M.at<double>(1, 2) += (nh / 2 - h / 2);
- 函数原型
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
- 参数列表
- SRC输入图像。
- DST输出图像,大小为dsize,类型与SRC相同。
- M 变换矩阵
- dsize输出图像大小。
- borderMode像素外推方法;当borderMode=#BORDER_TRANSPARENT时,表示目标图像中对应于源图像中“离群值”的像素不被函数修改。
- borderValue在边界不变的情况下使用的值;
案例
void QuickDemo::rotate_demo(Mat& image) {
Mat M, dst;
int w = image.cols;
int h = image.rows;
//获取变换矩阵
M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
int nw = w * cos + h * sin;
int nh = w * sin + h * cos;
M.at<double>(0, 2) += (nw / 2 - w / 2);
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(image, dst, M, Size(nw,nh ), INTER_LINEAR, 0, Scalar(0, 255, 0));
imshow("旋转", dst);
}