opencv(1)
quickopencv.h
#include <opencv2/opencv.hpp>
using namespace cv;
class quickdemo {
public:
void colorSpace_Demo(Mat &image);
};
quockdemo.cpp
色彩空间转换函数-cvtColor
#include "quickopencv.h"
void quickdemo::colorSpace_Demo(Mat &image) {
Mat gray, hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
cvtColor(image, gray, COLOR_BGR2GRAY);
namedWindow("HSV", WINDOW_FREERATIO);
imshow("HSV", hsv);
//色相h:0- 180 饱和度s 亮度v
namedWindow("灰度", WINDOW_FREERATIO);
imshow("灰度", gray);
imwrite("C:/Users/嘻嘻哈哈/Pictures/hsv.png",hsv);//三个参数 第一个是图像保存路径,第二个是图像内存对象
imwrite("C:/Users/嘻嘻哈哈/Pictures/gray.png", gray);
}
main.cpp
#include<opencv2/opencv.hpp>
#include<iostream>
#include "quickopencv.h"
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("C:/Users/嘻嘻哈哈/Pictures/微信图片_20210929221856.jpg");//由imread读出的照片都是8位的
namedWindow("输入窗口", WINDOW_FREERATIO);//可调大小的窗口形式
imshow("输入窗口", src);//只能输出8位的
quickdemo qd;
qd.colorSpace_Demo(src);
waitKey(0);
destroyAllWindows();
return 0;
}
opencv(2)
1.怎么操作Mat 以及怎么访问每一个像素点
void quickdemo::mat_creation_demo(Mat &image) {
Mat m1, m2;
m1 = image.clone();//克隆
image.copyTo(m2);//拷贝
//创建空白图像
Mat m3 = Mat::zeros(Size(40, 40), CV_8UC3); //CV_8UC1 :(Unsigned无符号的),(1:单通道的)8位
m3=Scalar(1, 1, 1);//通道赋值,知道几个通道就赋几个值,可通过他修改空白图像颜色
std::cout << "宽度:" << m3.cols << "高度:" << m3.rows << "通道数:" << m3.channels() << std::endl;
std::cout << m3 << std::endl;
imshow("创建图像", m3);
}
CV_8UC1:每个像素点的通道数是1
CV_8UC3:每个像素点的通道数是3
Mat m3 = Mat::ones(Size(8, 8), CV_8UC1);只会使第一个通道是1;
m3=Scalar(1, 1, 1);//通道赋值,知道几个通道就赋几个值,可通过他修改空白图像颜色
3.怎么创建一个空图或Mat
Mat之克隆m3.clone():修改m4不会对m3进行修改
Mat之克隆m3.copyTo(m4):修改m4不会对m3进行修改
Mat m3 = Mat::zeros(Size(40, 40), CV_8UC3);
m3=Scalar(1, 1, 1);
imshow("图像3", m3);
Mat m4 = m3.clone();//克隆
//m3.copyTo(m4);//copyTo复制
m4 = Scalar(200, 200, 200);
imshow("图像4", m4);
运行结果:
Mat之赋值m3=m4:修改m4会对m3进行修改
imshow("图像3", m3);
Mat m4 =m3;
m4 = Scalar(200, 200, 200);
imshow("图像3", m3);
运行结果:
前两者相当于深拷贝,后者相当于浅拷贝
重载运算符=是浅拷贝,共享内存空间,互相影响,clone是深拷贝,内存空间不同,相互独立,互不打扰;
opencv(3):对图像像素读写操作
1、基于数组:
void quickdemo::pixel_visit_demo(Mat &image) {
int w = image.cols;//宽,列
int h = image.rows;//高,行
int dims = image.channels();//通道数,等于1代表是灰度图像,等于3代表是彩色图像
for (int row = 0; row < h; row++) {//双重for循环
for (int col = 0; col < w; col++) {
if (dims == 1) {//灰度图像
int pv = image.at<uchar>(row, col);//将像素点转变为int类型,获取到一个值
image.at<uchar>(row, col) = 255 - pv;//uchar范围:0-255(2的8次方)
}
if (dims == 3) {//彩色图像
Vec3b bgr=image.at<Vec3b>(row, col);//浮点数就是Veb3f,获取到三个值,相当于一个数组
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);
}
运行结果:
2、基于指针:速度要快于数组(i++ 用的巧妙)
void quickdemo::pixel_visit_demo(Mat &image) {
int w = image.cols;//宽,列
int h = image.rows;//高,行
int dims = image.channels();//通道数,等于1代表是灰度图像,等于3代表是彩色图像
for (int row = 0; row < h; row++) {//双重for循环
uchar *current_row = image.ptr<uchar>(row);//指针指向这一行,获取这一行的地址
for (int col = 0; col < w; col++) {
if (dims == 1) {//灰度图像
int pv = *current_row;//将像素点转变为int类型,获取到这个地址的值
*current_row++ = 255 - pv;//++的是列数,即cols
}
if (dims == 3) {//彩色图像
Vec3b bgr = image.at<Vec3b>(row, col);//浮点数就是Veb3f,获取到三个值,相当于一个数组
*current_row++ = 255 - *current_row;//先减再自加,三行则是对三个通道都进行操作
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
imshow("像素读写显示",image);
}
运行结果:与上面图一样
opencv(4):对图像像素算数操作
加减乘除都不会超过255也不会小于0,若超过255则会默认调至255,小于0则默认为0
multiply(image, m, dst);//乘法
divide(image, m, dst);//除法
add(image, m, dst);//加法
subtract(image, m, dst);//减法
void quickdemo::operators_demo(Mat &image) {
Mat dst;
//dst = image + Scalar(50, 50, 50);//加法操作,图像变亮,减法变暗
//imshow("加法操作",dst);
//dst = image * Scalar(2, 2, 2);乘法操作,不可直接乘,要用专业函数multiply(乘数1,乘数2,积)
Mat m = Mat::zeros(image.size(), image.type());//创建一个和传过来的图片大小、类型相同的图像
m = Scalar(2, 2, 2);
multiply(image, m, dst);//乘法
divide(image, m, dst);//除法
add(image, m, dst);//加法
subtract(image, m, dst);//减法
imshow("乘法操作", dst);
}
乘法运行结果:
opencv(5):滚动条操作演示-调整图像亮度
createTrackbar()函数:通过改变滑动条的位置来改变函数里面变量的值
函数有6个参数:
参数1:轨迹条名字
参数2:窗口名字
参数3:滑块初始位置
参数4:表示滑块达到最大位置的值
参数5:默认值为0,指向回调函数
参数6:默认值为0,用户传给回调函数的数据值
createTrackbar("Value Bar", "亮度调整", &lightness, max_value, on_track,(void*)(&image));
static void on_track(int b, void* userdata) {//回调函数
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m= Mat::zeros(image.size(), image.type());
m = Scalar(b, b, b);
subtract(image, m, dst);
imshow("亮度调整", dst);
}
void quickdemo::tracking_bar_demo(Mat &image) {
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int max_value = 100;
int lightness = 50;
createTrackbar("Value Bar", "亮度调整", &lightness, max_value, on_track,(void*)(&image));
on_track(50, &image);
}
效果展示:
addWeighted()函数是将两张相同大小,相同类型的图片融合的函数
六个参数:
参数1:src1,第一个原数组.
参数2:alpha,第一个数组元素权重
参数3:src2第二个原数组
参数4:beta,第二个数组元素权重
参数5:gamma,图1与图2作和后添加的数值。
参数6:dst,输出图片
eg:
addWeighted(src1,0.5,src2,0.7,3,dst);
参数分别为:图1,图1的权重,图2,图2的权重,权重和添加的值为3,输出图片src
对比度调整:
注意:imshow里面的名称要统一,否则会出现错误
代码如下:
static void on_lightness(int b, void* userdata) {//回调函数,亮度调整
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m= Mat::zeros(image.size(), image.type());
addWeighted(image,1.0,m,0,b,dst);
imshow("亮度与对比度调整", dst);
}
static void on_contract(int b, void* userdata) {//回调函数,对比度调整
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
double contrast = b / 100.0;
addWeighted(image, contrast, m, 0.0, b, dst);
imshow("亮度与对比度调整", dst);
}
void quickdemo::tracking_bar_demo(Mat &image) {
namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE);
int lightness = 50;
int max_value = 100;//亮度调整
int contrast_value = 100;
createTrackbar("Value Bar", "亮度与对比度调整", &lightness, max_value, on_lightness,(void*)(&image));
createTrackbar("Contrast Bar", "亮度与对比度调整", &lightness, max_value, on_contract, (void*)(&image));
on_lightness(50, &image);
on_contract(50, &image);
}