opencv读入图像、灰度化、归一化、向量化

本文介绍如何利用OpenCV库在Win7环境下,通过C++与VS2008实现图像的基本处理流程,包括图像的读取、灰度化、尺度归一化以及图像向量化操作。

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

平台:win7+opencv2.4.4+vs2008

功能:实现对图像的读入、灰度化、归一化和向量化。

代码:

//这里的头文件都是vs2008的,与vc6.0有多不同
#include <opencv2\opencv.hpp>  
#include<iostream>
using namespace std;
using namespace cv;
void main(int argc, char* argv[])


{


	IplImage *src;
	src = cvLoadImage("D:\\image.jpg"); //这里将lena.jpg和lena.cpp文件放在同一个文件夹下
	cvNamedWindow("src",CV_WINDOW_AUTOSIZE);
	cvMoveWindow("src",0,50);
	cvShowImage("src",src);




	//图像灰度化  
	IplImage* gray_image;
	gray_image = cvCreateImage(cvGetSize(src),8,1);  
	cvCvtColor(src,gray_image,CV_BGR2GRAY);
//	cvNamedWindow("gray",CV_WINDOW_AUTOSIZE);
//	cvMoveWindow("gray",100,100);
//	cvShowImage("gray",gray_image);


	//尺度归一化  
	IplImage* norm_image;
	CvSize norm_cvsize;
	norm_cvsize.width = 100;  //目标图像的宽  
	norm_cvsize.height = 100; //目标图像的高
	norm_image = cvCreateImage(norm_cvsize, gray_image->depth,gray_image->nChannels); //构造目标图象  
	cvResize(gray_image, norm_image, CV_INTER_LINEAR); //缩放源图像到目标图像
//	cvNamedWindow("norm",CV_WINDOW_AUTOSIZE);
//	cvMoveWindow("norm",150,150);
//	cvShowImage("norm",norm_image);


	//图像转化成矩阵
	CvMat* norm_mat = cvCreateMat(norm_image->height,norm_image->width,CV_32FC1);//定义一个指向CvMat对象的指针
	cvConvert(norm_image,norm_mat);


	//变成行向量(默认为行向量)
	CvMat vecHead,*vecRow;
	vecRow=cvReshape( norm_mat, &vecHead, 0, 1 );//vec是得到的一维向量


	//矩阵转置从而得到列向量
	CvMat* col_mat = cvCreateMat(norm_image->height,norm_image->width,CV_32FC1);
	cvTranspose( norm_mat, col_mat ); 
	//变成列向量(获得列向量需要装置矩阵)
	CvMat colHead,*vecCol;
	vecCol=cvReshape( col_mat, &colHead, 0, 1 );//得到的一维向量


	


	//显示向量元素	
	int S=norm_cvsize.width*norm_cvsize.width;
	//给列向量赋值


	float c=0,col[10000]={0};

	float *p;//获得矩阵元素(0,0)的指针
	p =  (float*)cvPtr1D(vecCol, 0,0);
	for(int i = 0; i <S; i++)
    {
//		printf("%f\t",*p/255);
		col[i]=*p/255;
		c=col[i];
		printf("%f\t",c);
		p++;


    }


	cvWaitKey(0);//按需要0课改为任意值
	cvDestroyAllWindows();
	cvReleaseImage(&src);
	cvReleaseImage(&gray_image);
	cvReleaseImage(&norm_image);

	cvReleaseMat(&norm_mat);


	system("pause");//可加可不加


}



本代码经本人调试均已通过,而且已得到应用。

<think>我们被要求使用C++和OpenCV实现灰度变换曲线的函数。灰度变换通常用于图像增强,通过调整图像的灰度级来改善图像质量或突出某些特征。根据引用[3],灰度变换函数包括线性函数、对数函数、Gamma变换、分段线性变换等。用户要求的是“灰度变换曲线”,这可能是一种通用的灰度变换方法,允许用户定义任意的映射曲线。我们可以通过查找表(LookUpTable,LUT)来实现任意灰度变换曲线。因为灰度变换本质上是一个点操作,即每个像素的输出值只依赖于输入值,而与位置无关。因此,我们可以预先计算一个映射表,然后使用OpenCV的LUT函数应用这个映射。步骤:1.创建一个大小为256(对于8位灰度图像)的查找表(数组),该数组的下标是输入灰度级,值是对应的输出灰度级。2.根据用户指定的变换曲线(函数)填充这个查找表。3.对输入图像的每个像素,应用这个查找表进行映射。在OpenCV中,我们可以使用`cv::LUT()`函数来实现。注意,该函数可以处理多通道图像,但我们这里只考虑灰度图像(单通道)。如果输入是彩色图像,我们需要先转换为灰度图像,或者对每个通道分别应用变换(但通常灰度变换用于灰度图像)。假设用户希望实现一个任意的变换曲线,我们可以提供一个函数来生成查找表。例如,如果我们想实现一个线性变换(如对比度拉伸),或者Gamma校正,或者自定义的分段线性变换等。下面是一个示例,展示如何通过一个通用的函数来创建查找表,然后应用它。为了灵活性,我们可以将查找表生成部分独立出来,根据不同的变换函数来生成不同的查找表。示例:实现Gamma校正的灰度变换。Gamma校正的公式为:$O=I^{1/\gamma}\times\text{constant}$,通常我们会对图像进行归一化,然后进行Gamma校正,最后再恢复到[0,255]范围。但是,为了更通用,我们可以允许用户传入一个函数(比如lambda表达式)来定义任意的映射关系。然而,考虑到我们只能使用C++11或OpenCV支持的特性,我们可以这样设计:方法1:预先定义几种常见的灰度变换函数(线性、对数、Gamma、分段线性),并让用户指定参数。方法2:提供一个接口,允许用户传入一个向量(大小为256)作为查找表。这里,我们先展示一个使用Gamma校正的例子,然后展示一个通用的查找表应用方法,用户可以根据需要生成查找表。代码示例1:Gamma校正步骤:-归一化图像到[0,1]范围(若输入是8位,则除以255.0)-应用Gamma校正:O=I^(gamma)-将结果缩放回[0,255]但是,我们可以直接创建查找表避免对每个像素进行浮点运算。代码示例2:自定义查找表(比如反转图像)但是用户要求的是“灰度变换曲线”,可能是任意曲线,所以我们可以编写一个函数,该函数接受一个映射函数(如std::function<double(double)>)并生成查找表。然而,在OpenCV中,我们通常直接创建查找表数组,然后应用。下面我们给出两种方式的示例:方式A:固定变换(例如Gamma变换)方式B:允许用户自定义一个映射函数生成查找表为了满足用户需求,我们提供一个通用的函数,该函数可以接受一个函数对象,这个函数对象定义了输入强度到输出强度的映射(映射范围[0,255]到[0,255])。然后,我们使用这个映射函数生成查找表。注意:查找表是`cv::Mat`类型,通常是一个1x256的8位单通道矩阵。由于OpenCV的LUT函数要求查找表和输入图像有相同的通道数?实际上,对于多通道图像,查找表可以是一维的(每个通道使用相同的变换)或者与通道数匹配的多维(这里我们不涉及)。我们这里只处理灰度图像,所以查找表是单通道的。以下是具体步骤:1.创建一个查找表矩阵(1维,256个元素,类型为uchar)。2.对于每个灰度值i(0到255),应用映射函数得到映射后的值。注意,映射后的值应该在[0,255]之间,并转换为uchar。3.使用cv::LUT函数将查找表应用到输入图像。映射函数可以由用户提供,例如一个函数指针、函数对象或lambda表达式。下面我们给出一个示例代码,其中包含一个名为`createLookUpTable`的函数,它接受一个映射函数并返回查找表。然后,在`main`函数中,我们使用这个查找表对图像进行变换。为了演示,我们将实现一个Gamma校正的变换和一个反转变换。注意:Gamma校正需要将输入归一化,计算幂次,然后再还原到[0,255]。我们也可以实现分段线性变换,但为了简单起见,我们先实现通用的查找表生成。代码示例:首先,我们编写一个函数,生成查找表:cv::MatcreateLookUpTable(conststd::function<double(double)>&func){cv::Matlut(1,256,CV_8U);//创建一个1行256列的8位无符号整数矩阵uchar*p=lut.ptr<uchar>();for(inti=0;i<256;++i){doublevalue=func(static_cast<double>(i));//应用函数//确保值在0到255之间if(value<0)value=0;if(value>255)value=255;p[i]=static_cast<uchar>(value);}returnlut;}然后,我们可以用不同的函数来生成不同的查找表,例如:1.Gamma校正函数(gamma为参数):autogammaFunc=[gamma](doubleinput)->double{//归一化到[0,1]doublenormalized=input/255.0;doublecorrected=pow(normalized,gamma);returncorrected*255.0;};2.图像反转:autoinvertFunc=[](doubleinput)->double{return255.0-input;};3.线性变换(对比度调整):O=alpha*I+betaautolinearFunc=[alpha,beta](doubleinput)->double{returnalpha*input+beta;};在main函数中,我们可以这样使用://读入图像(灰度)cv::Matsrc=cv::imread("input.jpg",cv::IMREAD_GRAYSCALE);if(src.empty()){std::cerr<< "Couldnotopenimage!"<< std::endl;return-1;}//创建查找表(例如,使用Gamma校正,gamma=0.5)doublegamma_val=0.5;autogammaFunc=[gamma_val](doubleinput)->double{returnpow(input/255.0,gamma_val)*255;};cv::Matlut=createLookUpTable(gammaFunc);//应用查找表cv::Matdst;cv::LUT(src,lut,dst);注意:这里我们假设输入图像是8位的。如果图像是16位或浮点数,则查找表需要相应调整。另外,分段线性变换可以通过定义多个线段来构建变换函数,我们可以单独写一个函数来生成分段线性变换的查找表。下面我们编写一个函数来创建分段线性变换的查找表。分段线性变换由一系列点定义,这些点将[0,255]区间分成若干段,每段是线性的。例如,我们定义几个关键点:(0,0),(100,50),(200,220),(255,255)然后,在相邻的两个点之间进行线性插值。函数原型:cv::MatcreatePiecewiseLinearLUT(conststd::vector<cv::Point>&points);但是,为了方便,我们可以直接写一个函数来生成,然后返回查找表。注意,点应该是按x坐标排序的。由于时间关系,我们不在这里实现,但如果有需要,我们可以扩展。综上所述,我们提供给用户的示例代码将包括:-通用的查找表生成函数(使用自定义映射函数)-示例:Gamma校正-示例:图像反转-示例:对比度拉伸(线性变换)我们将主函数中演示Gamma校正和反转。注意:用户可能需要将图像转换为灰度图,如果输入是彩色的话。但题目要求灰度变换,所以我们的代码假设输入是灰度图像。如果不是,我们可以先转换为灰度图像。下面我们写出完整的代码示例。</think> ### 使用C++和OpenCV实现灰度变换曲线函数 以下是使用C++和OpenCV实现通用灰度变换曲线的完整示例代码。该函数通过查找表(LUT)实现任意灰度级映射,支持自定义变换曲线: ```cpp #include <opencv2/opencv.hpp> #include <vector> using namespace cv; // 灰度变换曲线函数 Mat applyGrayTransform(Mat inputImage, const std::vector<Point>& curvePoints) { // 验证输入曲线点的有效性 if (curvePoints.empty()) { return inputImage.clone(); // 无变换时返回原图 } // 创建查找表(LUT) Mat lut(1, 256, CV_8UC1); // 1行256列的查找表 // 生成LUT (使用线性插值) int startIdx = 0; for (int i = 0; i < curvePoints.size() - 1; ++i) { Point p1 = curvePoints[i]; Point p2 = curvePoints[i+1]; // 计算两点间的线段斜率 float slope = static_cast<float>(p2.y - p1.y) / (p2.x - p1.x); // 填充两点间的所有灰度级 for (int j = p1.x; j < p2.x; ++j) { int value = static_cast<int>(p1.y + slope * (j - p1.x)); lut.at<uchar>(j) = saturate_cast<uchar>(value); } startIdx = p2.x; } // 处理最后一个点 for (int j = startIdx; j < 256; ++j) { lut.at<uchar>(j) = saturate_cast<uchar>(curvePoints.back().y); } // 应用查找表到图像 Mat outputImage; LUT(inputImage, lut, outputImage); return outputImage; } int main() { // 读取图像 Mat src = imread("input.jpg", IMREAD_GRAYSCALE); // 灰度模式 if (src.empty()) { std::cerr << "Error: Could not load image" << std::endl; return -1; } // 定义灰度变换曲线(示例:S形曲线) std::vector<Point> curvePoints; curvePoints.push_back(Point(0, 0)); // 输入0 → 输出0 curvePoints.push_back(Point(100, 50)); // 低值区域增强 curvePoints.push_back(Point(150, 200)); // 中值区域快速上升 curvePoints.push_back(Point(255, 255)); // 最大值 // 应用变换 Mat dst = applyGrayTransform(src, curvePoints); // 显示结果 imshow("Original", src); imshow("Gray Transform", dst); waitKey(0); return 0; } ``` ### 实现说明 1. **核心功能**: - 创建`applyGrayTransform`函数处理任意灰度映射 - 使用查找表(LUT)实现高效像素变换 - 支持自定义控制点定义变换曲线 - 通过线性插值生成平滑过渡曲线 2. **参数详解**: ```cpp /** * @param inputImage 输入灰度图像(8位单通道) * @param curvePoints 变换曲线控制点(vector<Point>) * x: 输入灰度级(0-255) * y: 对应输出灰度级(0-255) * @return 变换后的图像 */ Mat applyGrayTransform(Mat inputImage, const std::vector<Point>& curvePoints) ``` 3. **自定义曲线示例**: - **对比度拉伸**:`{Point(0,0), Point(80,0), Point(180,255), Point(255,255)}` - **伽马校正**:`{Point(0,0), Point(pow(i,gamma)*255, i)} for i in [0,255]` - **图像反转**:`{Point(0,255), Point(255,0)}` - **阈值处理**:`{Point(0,0), Point(127,0), Point(128,255), Point(255,255)}` ### 关键函数参考[^3] 1. **LUT()**: 查找表变换函数,高效实现像素级映射 `void LUT(InputArray src, InputArray lut, OutputArray dst)` 2. **saturate_cast()**: 确保输出值在有效范围(0-255)内 `uchar saturate_cast<uchar>(int value)` ### 应用场景 - 医学影像增强 - 低照度图像处理 - 图像分割预处理 - 印刷品质量优化 图像增强技术通过调整灰度映射关系改善图像视觉效果,是计算机视觉预处理的关键环节[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值