Opencv学习day03
出入每天学习点OpenCV,做做计算机视觉项目
文章目录
前言
为了项目与论文需要,现在入门 OpenCV4学习,并且学习点深度学习的东西,希望有助于自身论文的研究,只是为了毕业。。。
一、内容
1. 颜色空间的缩减
有时有些关键像素就能表示出整幅图,为了减少计算量,可以对颜色空间进行缩减。
对于unchar类型只有0-255个值,进行颜色空间的缩减时可以//0-9用0替代,10-19-用10替代,20-29用20替代…以此类推。
涉及到知识点:
图像每个像素的访问方式:
1、利用指针访问像素值
2、利用at()函数访问像素
3、利用迭代器iterator访问像素
获取系统时间方式:
getTickCount();获取系统的振荡次数
getTickFrequency() 系统振荡频率
时间 = getTickCount()/getTickFrequency()
代码:
//颜色空间缩减
void OpenCV_quick_day01Demo::colorSpaceReduction_demo(Mat &image) {
//0-9用0替代,10-19-用10替代,20-29用20替代
//由于uchar只有0-255个像素,先建立一张表,存储可能的值
uchar table[256];
int dividewith = 10;
int width = image.cols *image.channels();
int heigth = image.rows;
double startTime = static_cast<double>(getTickCount())/ getTickFrequency();
for (int i = 0; i < 256; i++)
{
table[i] = (i / dividewith)*dividewith;
}
//访问图片每一个像数值
//利用指针访问像素值
for (int i = 0; i < heigth; i++) {
uchar * current_row = image.ptr<uchar>(i);
for (int j = 0; j < width; j++)
{
current_row[j] = table[current_row[j]];
}
}
//利用at()函数访问像素
/*for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < image.cols; j++)
{
image.at<Vec3b>(i, j)[0] = table[image.at<Vec3b>(i, j)[0]];
image.at<Vec3b>(i, j)[1] = table[image.at<Vec3b>(i, j)[1]];
image.at<Vec3b>(i, j)[2] = table[image.at<Vec3b>(i, j)[2]];
}
}*/
//利用迭代器访问像素点
/*
Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
for (; it != itend; it++) {
(*it)[0] = table[(*it)[0]];
(*it)[1] = table[(*it)[1]];
(*it)[2] = table[(*it)[2]];
}
*/
double endTime = static_cast<double> (getTickCount())/ getTickFrequency();
double runTime = endTime - startTime;
imshow("colorSpaceReduction", image);
cout << "程序运行时间:" << runTime << endl;
}
2. 获取ROI区域
void OpenCV_quick_day01Demo::ROI_demo() {
Mat srcImage = imread("E:/OpenCVcode/imageRead/aloeR.jpg");
Mat logoImage = imread("E:/OpenCVcode/imageRead/apple.jpg");
Mat imageROI;
//在srcImage上,ROI 区域左顶点为(200,200),长logoImage.cols,宽logoImage.rows
imageROI = srcImage(Rect(200, 200, logoImage.cols, logoImage.rows));
Mat mask = imread("E:/OpenCVcode/imageRead/apple.jpg", 0);
logoImage.copyTo(imageROI, mask);
namedWindow("ROI", WINDOW_FREERATIO);
imshow("ROI", srcImage);
}
3. ROI 与线性叠加
addWeighted:
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype = -1);
第一个参数:要叠加的第一个图像Mat
第二个参数:标识第一个参数叠加的权重
第三个参数:表示第二个叠加的图像,他需要和第一个数组拥有同样的尺寸和通道数
第四个参数:表示第二个叠加图像的权重
第五个参数:输出参数,需要和前两个图像拥有同样的通道数和尺寸
第六个参数:一个加到权重总和上的标量值(填0就好)
第七个参数:输出阵列的深度有默认值-1, 当两张叠加图片深度相同时,参数为-1
对应表达式为:dst = src1[i] * alpha + src2[i] * beta + gamma;
void OpenCV_quick_day01Demo::ROI_LinearBlending() {
Mat srcImage = imread("E:/OpenCVcode/imageRead/aloeR.jpg");
Mat logoImage = imread("E:/OpenCVcode/imageRead/apple.jpg");
Mat imageROI;
imageROI = srcImage(Rect(200, 200, logoImage.cols, logoImage.rows));
addWeighted(imageROI, 0.5, logoImage, 0.3, 0.0, imageROI);
namedWindow("ROI", WINDOW_FREERATIO);
imshow("ROI_linearBlending",srcImage);
}
4. 离散傅里叶变换
getOptimalDFTSize:
int getOptimalDFTSize(int vecesize);返回DFT最优尺寸大小,vecesize向量尺寸,即图片的rows,cols
copyMakeBorder:
void copyMakeBorder(InputArray src, OutputArray dst,int top, int bottom,
int left, int right,int borderType,
const Scalar& value = Scalar() )
————扩充图像边沿尺寸
int top, int bottom,int left, int right,在原图像扩充多少像素
int borderType,边界类型常见取值,BORDER_CONSTANT
const Scalar& value = Scalar() :要填充的值。Scalar类型
magnitude:
void magnitude(InputArray x, InputArray y, OutputArray magnitude)计算二维矢量的幅值
InputArray x, 实部,, InputArray y,虚部 OutputArray magnitude 输出的幅值
dft:
void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);
对一维或二维浮点数数组进行正向或反向离散傅里叶变换
第一个参数:InputArray类型的src。输入矩阵,可以为实数或者虚数
第二个参数:OutputArray类型的dst。函数调用后的运算结果存在这里,其尺寸和类型取决于标识符,也就是第三个参数flags
第三个参数:int类型的flags。转换的标识符,有默认值0,取值可以为为下表:
第四个参数:int类型的nonzeroRows,默认值为0.当此参数设为非零时,函数会假设只有输入矩阵的第一个非零行包含非零元素,或只有输出矩阵的一个非零行包含非零元素。
normalize:
void normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())
归一化数据。
src 输入数组;
dst 输出数组,数组的大小和原数组一致;
alpha 1,用来规范值,2.规范范围,并且是下限;
beta 只用来规范范围并且是上限;//为0时则为值归一化,否则为范围归一化
norm_type 归一化选择的数学公式类型;
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
NORM_L1 : 归一化数组的L1-范数(绝对值的和)
NORM_L2: 归一化数组的(欧几里德)L2-范数
dtype 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;
mark 掩码。选择感兴趣区域,选定后只能对该区域进行操作。
void OpenCV_quick_day01Demo::dft_demo(Mat &image)//傅里叶变换
{
//原程序
//1、先将原图转化为灰度图,扩大原图像到合适尺寸,一般位2,3,5的整数倍最快。
//利用getOptimalDFTSize获得合适尺寸,再用copyMakeBorder扩展边缘像素
Mat srcImage;
cvtColor(image, srcImage, COLOR_BGR2GRAY);
int m = getOptimalDFTSize(srcImage.rows);
int n = getOptimalDFTSize(srcImage.cols);
cout << m << endl;
Mat newImage;
copyMakeBorder(srcImage, newImage, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0));
newImage.convertTo(newImage, CV_32F);
cout << newImage.size();
//2.为傅里叶变换的结果(实部和虚部),分配存储空间
Mat planes[] = { newImage, Mat::zeros(newImage.size(),CV_32F) };
Mat complex;
merge(planes, 2, complex);
//3.进行离散傅里叶变换
dft(complex, complex);
//4.将变换后的复数转换为幅值
Mat channels[2];
split(complex, channels);//先分离出实部和虚部
Mat magnitudeValue;
magnitude(channels[0], channels[1], magnitudeValue);//转换成幅值
//5.所得的幅值太大, 进行尺度缩放
magnitudeValue += Scalar::all(1);
log(magnitudeValue, magnitudeValue);
//6.剪切和重分布幅度图象限,一四象限对调,二三象限对调。
//若有奇数行或奇数列,进行频谱裁剪
magnitudeValue = magnitudeValue(Rect(0, 0, magnitudeValue.cols & -2, magnitudeValue.rows & -2));
int x = magnitudeValue.cols / 2;
int y = magnitudeValue.rows / 2;
//剪切幅度图象限
Mat q0 = magnitudeValue(Rect(0, 0, x, y));
Mat q1 = magnitudeValue(Rect(x , 0, x, y));
Mat q2 = magnitudeValue(Rect(0, y, x, y));
Mat q3 = magnitudeValue(Rect(x, y, x, y));
//重分布幅度图象限,一四交换,二三交换
Mat temp;
q0.copyTo(temp);
q3.copyTo(q0);
temp.copyTo(q3);
q1.copyTo(temp);
q2.copyTo(q1);
temp.copyTo(q2);
//归一化处理
normalize(magnitudeValue, magnitudeValue, 0, 1, NORM_MINMAX);
imshow("频谱幅值", magnitudeValue);
}