Opencv回顾--图像操作之反转*通道分离*缩放

本文回顾了OpenCV中的图像操作,包括如何翻转图像、进行通道分离,将三通道图像转化为单通道,以及使用scalar进行颜色设定。scalar可以用于设置图像的BGR分量值,例如全部设为零。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要函数
翻转图像

cv::flip(src, dst, flipCode);
 src    输入数组。
 dst   输出与src大小和类型相同的数组。
 flipCode 一个标志,指定如何翻转数组; 
0表示绕x轴翻转
正值翻转(例如,1)表示绕y轴翻转。
负值(例如,-1)表示翻转围绕两个轴。

通道分离

void cv::split(
	const cv::Mat& mtx, //输入图像
	vector<Mat>& mv // 输出的多通道序列(n个单通道序列)
);   
 void cv::split(
 const cv::Mat& mtx, //输入图像
 Mat &mv[3] // 输出的多通道序列(n个单通道序列)
);

将三通道图像分离成单通道

合并图像

    void merge(const Mat* mv, size_t count, OutputArray dst);
    第一个参数是图像矩阵数组,
    第二个参数是需要合并矩阵的个数,
    第三个参数是输出
    
    void merge(const vector& mv, OutputArray dst );
    第一个参数是图像矩阵向量容器,
    第二个参数是输出,这种方法无需说明需要合并的矩阵个数,vector对象自带说明


    std::vector<Mat> channels;
    Mat aChannels[3]; 
    split(src, channels);              //分离到数组
    split(src, aChannels);             //分离到vector对象
    
    merge(channels, 3, mergeImg);

scalar是设置bgr分量的值,相当于配色
scalar(0,0,0)
scalar

#include <opencv2/opencv.hpp> #include <cmath> #include <complex> #include <vector> #include <iostream> using namespace cv; using namespace std; // 位反转函数(用于蝶形运算准备) int bitReverse(int num, int log2n) { int result = 0; for (int i = 0; i < log2n; ++i) { if (num & (1 << i)) result |= 1 << (log2n - 1 - i); } return result; } // 1D FFT实现(基2-FFT蝶形运算) void fft(vector<complex<float>>& data, bool inverse = false) { const int n = data.size(); const int log2n = static_cast<int>(log2(n)); // 位反转重排 vector<complex<float>> temp(n); for (int i = 0; i < n; ++i) { int rev = bitReverse(i, log2n); temp[i] = data[rev]; } // 蝶形运算 for (int s = 1; s <= log2n; ++s) { int m = 1 << s; // 当前处理块大小 float ang = 2 * CV_PI / m * (inverse ? 1 : -1); complex<float> wm(cos(ang), sin(ang)); for (int k = 0; k < n; k += m) { complex<float> w(1.0f); for (int j = 0; j < m / 2; ++j) { complex<float> t = w * temp[k + j + m / 2]; complex<float> u = temp[k + j]; temp[k + j] = u + t; temp[k + j + m / 2] = u - t; w *= wm; } } } // 逆变换缩放 if (inverse) { for (auto& x : temp) x /= n; } data = temp; } // 2D FFT实现 void fft2d(Mat& complexImage, bool inverse = false) { int rows = complexImage.rows; int cols = complexImage.cols; // 行变换 for (int y = 0; y < rows; ++y) { vector<complex<float>> rowData; for (int x = 0; x < cols; ++x) { rowData.push_back(complexImage.at<Vec2f>(y, x).val[0] + complexImage.at<Vec2f>(y, x).val[1] * 1if); } fft(rowData, inverse); for (int x = 0; x < cols; ++x) { complexImage.at<Vec2f>(y, x) = Vec2f(rowData[x].real(), rowData[x].imag()); } } // 列变换 for (int x = 0; x < cols; ++x) { vector<complex<float>> colData; for (int y = 0; y < rows; ++y) { colData.push_back(complexImage.at<Vec2f>(y, x).val[0] + complexImage.at<Vec2f>(y, x).val[1] * 1if); } fft(colData, inverse); for (int y = 0; y < rows; ++y) { complexImage.at<Vec2f>(y, x) = Vec2f(colData[y].real(), colData[y].imag()); } } } // 频域中心化 (fftshift) void fftShift(Mat& mag) { int cx = mag.cols / 2; int cy = mag.rows / 2; Mat q0(mag, Rect(0, 0, cx, cy)); Mat q1(mag, Rect(cx, 0, cx, cy)); Mat q2(mag, Rect(0, cy, cx, cy)); Mat q3(mag, Rect(cx, cy, cx, cy)); Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); } // 计算MSE double calculateMSE(const Mat& img1, const Mat& img2) { if (img1.size() != img2.size() || img1.type() != img2.type()) { cerr << "Images must have same size and type" << endl; return -1; } Mat diff; absdiff(img1, img2, diff); diff = diff.mul(diff); Scalar s = sum(diff); return s[0] / (img1.total() * img1.channels()); } // 计算PSNR double calculatePSNR(const Mat& img1, const Mat& img2) { double mse = calculateMSE(img1, img2); if (mse <= 1e-10) return 100; // 避免除以0 return 10.0 * log10((255.0 * 255.0) / mse); } // 创建高斯低通滤波器掩膜 Mat createGaussianLowPassFilter(Size size, double sigma) { Mat mask = Mat::zeros(size, CV_32F); Point center(size.width / 2, size.height / 2); for (int y = 0; y < size.height; y++) { for (int x = 0; x < size.width; x++) { double d = sqrt(pow(x - center.x, 2) + pow(y - center.y, 2)); mask.at<float>(y, x) = exp(-(d * d) / (2 * sigma * sigma)); } } return mask; } int main() { // 读取灰度图像 Mat img = imread("input.jpg", IMREAD_GRAYSCALE); if (img.empty()) { cerr << "Could not read image" << endl; return -1; } // 调整大小为2的幂次(FFT要求) int newRows = pow(2, ceil(log2(img.rows))); int newCols = pow(2, ceil(log2(img.cols))); resize(img, img, Size(newCols, newRows)); // 转换为浮点型并归一化 Mat floatImg; img.convertTo(floatImg, CV_32F, 1.0 / 255.0); // 准备复数矩阵(实部=图像,虚部=0) Mat planes[] = { Mat_<float>(floatImg), Mat::zeros(floatImg.size(), CV_32F) }; Mat complexImg; merge(planes, 2, complexImg); // ===== 执行FFT ===== fft2d(complexImg); // 分离实部和虚部 split(complexImg, planes); // 计算幅度谱 (log scale) Mat mag; magnitude(planes[0], planes[1], mag); mag += Scalar::all(1); // 避免log(0) log(mag, mag); normalize(mag, mag, 0, 1, NORM_MINMAX); // 频域中心化 fftShift(mag); // 显示幅度谱 imshow("Frequency Spectrum", mag); imwrite("spectrum.jpg", mag * 255); waitKey(0); // ===== 重建原始图像 (IFFT) ===== fft2d(complexImg, true); // 逆变换 // 获取实部作为重建图像 split(complexImg, planes); Mat reconstructed; normalize(planes[0], reconstructed, 0, 1, NORM_MINMAX); // 显示重建图像 imshow("Reconstructed Image", reconstructed); imwrite("reconstructed.jpg", reconstructed * 255); // 计算重建MSE/PSNR double mseOriginal = calculateMSE(floatImg, reconstructed); double psnrOriginal = calculatePSNR(floatImg, reconstructed * 255); cout << "MSE (Original): " << mseOriginal << endl; cout << "PSNR (Original): " << psnrOriginal << " dB" << endl; // =====高斯低通滤波处理 ===== // 创建高斯低通滤波器(截止频率=图像尺寸的15%) double sigma = min(img.rows, img.cols) * 0.08; // 调整截止频率参数 Mat lpfMask = createGaussianLowPassFilter(complexImg.size(), sigma); // 应用滤波器(在频域中心化状态) fftShift(mag); Mat filteredPlanes[] = { planes[0].mul(lpfMask), planes[1].mul(lpfMask) }; Mat filteredComplex; merge(filteredPlanes, 2, filteredComplex); // 逆变换得到滤波后图像 fft2d(filteredComplex, true); split(filteredComplex, filteredPlanes); Mat filteredImg; normalize(filteredPlanes[0], filteredImg, 0, 1, NORM_MINMAX); // 显示滤波后图像 imshow("高斯Low-Pass Filtered", filteredImg); imwrite("filtered.jpg", filteredImg * 255); // 计算滤波后PSNR double mseFiltered = calculateMSE(floatImg, filteredImg); double psnrFiltered = calculatePSNR(floatImg, filteredImg * 255); cout << "MSE (Filtered): " << mseFiltered << endl; cout << "PSNR (Filtered): " << psnrFiltered << " dB" << endl; waitKey(0); return 0; }
最新发布
06-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值