实验一 熟悉OpenCV环境和基本操作
一、实验目的
熟悉OpenCV运行环境,了解图像的基本操作及直方图均衡化。
二、实验内容
一个简单的图像处理例子。
代码如下:
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
Mat img = imread("result1.bmp");
int nr = img.rows; // number of rows
int nc = img.cols; // number of columns
Mat result;
result.create(img.rows, img.cols, img.type());
for (int j = 0; j < nr; j++) {
for (int i = 0; i < nc; i++) {
result.at<uchar>(j, i) = 255 - img.at<uchar>(j, i);
} // end of row
}
namedWindow("source");
imshow("source", img);
namedWindow("result");
imshow("result", result);
waitKey(0);
return 0;
}
三、实验要求
1.按上述代码运行,能不能得出正确结果?如果不能,请修改代码。
2.利用OpenCV产生一幅图像,尺寸为200*240,三通道,其中某一块为红色,其它皆为黑色,示例图如下。
- 对一幅低对比度图像进行增强处理,分别采用直方图均衡化、对比拉伸和幂次变换的方法,比较处理结果。
直方图均衡化算法步骤如下:
- 统计直方图数组,用一个数组p记录p[i];
- i从1开始,令S[i]=S[i-1]+p[i],S[0]=p[0];
- 一个数组L记录新的S索引值,即令L[i]=S[i]*(256-1);
依次循环每一个像素,取原图的像素值作为数组L的下标值,取该下标对应的数组值为均衡化之后的像素值。
四、实验报告要求
1.给出简要的设计思路(原理)
<1>通过result.at<Vec3b>(j, i)[?]访问不同通道
<2>通过将像素数均分为相等的小块,正方形各占长宽相同数量的像素即可,然后再做一些偏移
<3>
//直方图均衡化
首先计算原始图像的直方图,然后计算直方图的累积分布函数,接着计算映射后的灰度级,最后用新的映射关系修改原始图像的灰度级,获得直方图近似均匀分布的输出图像。这种处理方式使得原始图像中具有相近灰度且占有大量像素点的区域灰度范围展宽,同时使占有较少像素的灰度级变换后和前一个灰度级的级差减小,从而增强图像的对比度和清晰度。
//拉伸
将整体图片的像素压缩到某段区间内
//幂次变换
将图片的某些像素灰度提高,某些降低
2.给出主要代码
<1> for (int j = 0; j < nr; j++) {
for (int i = 0; i < nc; i++) {
result.at<Vec3b>(j, i)[0] = 255 - img.at<Vec3b>(j, i)[0];
result.at<Vec3b>(j, i)[1] = 255 - img.at<Vec3b>(j, i)[1];
result.at<Vec3b>(j, i)[2] = 255 - img.at<Vec3b>(j, i)[2];
}
}
<2> Mat img = imread("H://文档//Tencent Files//ASE//1.jpg");
int nr = 240; // number of rows
int nc = 200; // number of columns
Mat result;
result.create(nr, nc,img.type());
for (int j = 0; j < nr; j++) {
for (int i = 0; i < nc; i++) {
result.at<Vec3b>(j, i)[0] = 0;
result.at<Vec3b>(j, i)[1] = 0;
result.at<Vec3b>(j, i)[2] = 0;
}
}
for (int j = 2*nc / 5; j < 3*nc/5; j++) {
for (int i = 2*nr/6; i < 3*nr/6; i++) {
result.at<Vec3b>(j, i)[0] = 0;
result.at<Vec3b>(j, i)[1] = 0;
result.at<Vec3b>(j, i)[2] = 255;
}
}
namedWindow("result");
imshow("result", result);
<3>//直方图均衡化
Mat img = imread("H://文档//Tencent Files//ASE//1.jpg",0);
Mat result1;
CV_Assert(img.type() == CV_8UC1);
result1.create(img.size(), img.type());
int histSize = 256; // 像素值范围
int total = img.rows * img.cols; // 总像素数
// 计算直方图
vector<int> hist(histSize, 0);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
hist[img.at<uchar>(i, j)]++;
}
}
// 计算累积分布函数(CDF)
vector<float> cdf(histSize, 0);
cdf[0] = hist[0];
for (int i = 1; i < histSize; i++) {
cdf[i] = cdf[i - 1] + hist[i];
}
// 归一化CDF
for (int i = 0; i < histSize; i++) {
cdf[i] = cdf[i] / total;
}
// 应用直方图均衡化
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
uchar pixel = img.at<uchar>(i, j);
result1.at<uchar>(i, j) = static_cast<uchar>(cdf[pixel] * 255);
}
}
//拉伸
double minVal, maxVal;
minMaxLoc(img, &minVal, &maxVal); // 查找图像的最小和最大像素值
result = img.clone();
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
result.at<uchar>(i, j) = static_cast<uchar>(255.0 * (img.at<uchar>(i, j) - minVal) / (maxVal - minVal));
}
}
//幂次变换
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
result.at<uchar>(i, j) = static_cast<uchar>(pow(img.at<uchar>(i, j) / 255.0, gamma) * 255.0);
}
}
3.给出实验结果的屏幕截图
- 实验过程中遇到的主要问题、心得体会或建议
这三种方法都旨在增强图像的对比度,但它们各自采用不同的技术路径。直方图均衡化通过调整图像的直方图分布来实现对比度增强,对比拉伸通过拉伸图像的灰度级范围来增强对比度,而幂次变换则通过对图像的每个像素应用幂律函数来调整对比度。这展示了在图像处理中达到相似目的的多种方法。
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void func1() {
Mat img = imread("H://文档//Tencent Files//ASE//1.jpg");
int nr = 240; // number of rows
int nc = 200; // number of columns
Mat result;
result.create(nr, nc,img.type());
for (int j = 0; j < nr; j++) {
for (int i = 0; i < nc; i++) {
result.at<Vec3b>(j, i)[0] = 0;
result.at<Vec3b>(j, i)[1] = 0;
result.at<Vec3b>(j, i)[2] = 0;
} // end of row
}
for (int j = 2*nc / 5; j < 3*nc/5; j++) {
for (int i = 2*nr/6; i < 3*nr/6; i++) {
result.at<Vec3b>(j, i)[0] = 0;
result.at<Vec3b>(j, i)[1] = 0;
result.at<Vec3b>(j, i)[2] = 255;
} // end of row
}
namedWindow("result");
imshow("result", result);
waitKey(0);
}
void func2() {
Mat img = imread("H://文档//Tencent Files//ASE//1.jpg",0);
Mat result1;
CV_Assert(img.type() == CV_8UC1);
result1.create(img.size(), img.type());
int histSize = 256; // 像素值范围
int total = img.rows * img.cols; // 总像素数
// 计算直方图
vector<int> hist(histSize, 0);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
hist[img.at<uchar>(i, j)]++;
}
}
// 计算累积分布函数(CDF)
vector<float> cdf(histSize, 0);
cdf[0] = hist[0];
for (int i = 1; i < histSize; i++) {
cdf[i] = cdf[i - 1] + hist[i];
}
// 归一化CDF
for (int i = 0; i < histSize; i++) {
cdf[i] = cdf[i] / total;
}
// 应用直方图均衡化
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
uchar pixel = img.at<uchar>(i, j);
result1.at<uchar>(i, j) = static_cast<uchar>(cdf[pixel] * 255);
}
}
namedWindow("img");
imshow("img", img);
namedWindow("直方图均衡化");
imshow("直方图均衡化", result1);
}
void func3() {
Mat img = imread("H://文档//Tencent Files//ASE//1.jpg", 0);
Mat result;
CV_Assert(img.type() == CV_8UC1);
double minVal, maxVal;
minMaxLoc(img, &minVal, &maxVal); // 查找图像的最小和最大像素值
result = img.clone();
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
result.at<uchar>(i, j) = static_cast<uchar>(255.0 * (img.at<uchar>(i, j) - minVal) / (maxVal - minVal));
}
}
namedWindow("拉伸");
imshow("拉伸", result);
}
void func4() {
Mat img = imread("H://文档//Tencent Files//ASE//1.jpg", 0);
Mat result;
float gamma = 2.0;
CV_Assert(img.type() == CV_8UC1);
result = img.clone();
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
result.at<uchar>(i, j) = static_cast<uchar>(pow(img.at<uchar>(i, j) / 255.0, gamma) * 255.0);
}
}
namedWindow("幂次变换");
imshow("幂次变换", result);
waitKey(0);
}
int main() {
func2();
func3();
func4();
return 0;
}