天天看點

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

實驗内容及實驗原理:

1、灰階的線性變換

灰階的線性變換就是将圖像中所有的點的灰階按照線性灰階變換函數進行變換。該線性灰階變換函數是一個一維線性函數:f(x)=a*x+b

其中參數a為線性函數的斜率,b為線性函數的在y軸的截距,x表示輸入圖像的灰階,f(x)表示輸出圖像的灰階。

要求:輸入一幅圖像,根據輸入的斜率和截距進行線性變換,并顯示。

2、灰階拉伸

灰階拉伸和灰階線性變換相似。不同之處在于它是分段線性變換。表達式如下:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

其中,x1和x2是分段函數的轉折點。

要求:輸入一幅圖像,根據選擇的轉折點,進行灰階拉伸,顯示變換後的圖像。

3、灰階直方圖

灰階直方圖是灰階值的函數,描述的是圖像中具有該灰階值的像素的個數,其橫坐标表示像素的灰階級别,縱坐标表示該灰階出現的頻率(象素的個數)。

要求:輸入一幅圖像,顯示它的灰階直方圖,可以根據輸入的參數(上限、下限)顯示特定範圍的灰階直方圖。

4、直方圖均衡:要求

1)    顯示一幅圖像pout.bmp的直方圖;

2)    用直方圖均衡對圖像pout.bmp進行增強;

3)    顯示增強後的圖像。

實驗過程:

打開原圖像,建立結果圖像:

IplImage *src = cvLoadImage("pout.bmp", 1);//原圖
IplImage *dst =cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
           

函數說明:

CVAPI(IplImage*)cvLoadImage( constchar* filename, intiscolorCV_DEFAULT (CV_LOAD_IMAGE_COLOR));

//Iscolor的值:
enum{
/* 8bit, color ornot */  CV_LOAD_IMAGE_UNCHANGED  =-1,
/* 8bit, gray */         CV_LOAD_IMAGE_GRAYSCALE  =0,
/* ?, color */           CV_LOAD_IMAGE_COLOR      =1,
/* any depth, ? */       CV_LOAD_IMAGE_ANYDEPTH   =2,
/* ?, any color */       CV_LOAD_IMAGE_ANYCOLOR   =4,
/* ?, no rotate */       CV_LOAD_IMAGE_IGNORE_ORIENTATION  =128
};

CVAPI(IplImage*)  cvCreateImage( CvSizesize, intdepth, intchannels );
@param size Imagewidth and height
@param depth Bitdepth of image elements. See IplImage for valid depths.
@param channelsNumber of channels per pixel. See IplImage for details. This function onlycreates
images withinterleaved channels.
           

圖像顯示:

cvNamedWindow("Image", 1);//建立視窗
cvShowImage("Image", dst);//顯示圖像,在指定視窗顯示制定圖像
cvWaitKey(0); //等待按鍵
cvDestroyWindow("Image");//銷毀視窗

//函數說明
CVAPI(int)cvNamedWindow( constchar* name, intflagsCV_DEFAULT(CV_WINDOW_AUTOSIZE) );
Flags:
CV_WINDOW_NORMAL   =0x00000000, //the user canresize the window (no constraint)  / alsouse to switch a fullscreen window to a normal size
CV_WINDOW_AUTOSIZE = 0x00000001, //the user cannot resize the window, the size isconstrainted by the image displayed
CV_WINDOW_OPENGL   =0x00001000, //window with openglsupport
           

灰階線性變換

對圖像的每個像素周遊,擷取原圖像的灰階值,然後計算線性變換後的值,設定目标圖像相應位置的灰階值

for (int i = 0;i < src->height; i++){
     for (int j = 0; j < src->width; j++){
         CvScalar s =cvGet2D(src, i, j);
         s.val[0] = fa * s.val[0] + fb;
         cvSet2D(dst, i, j, s);
     }
}

//函數說明:
//參數為圖像指針和坐标,如果指定位置不存在則傳回0
CVAPI(CvScalar)cvGet2D( constCvArr* arr, intidx0, intidx1 );
The functions returna specific array element. In the case of a sparse array the functions return 0
if the requestednode does not exist (no new node is created by the functions).
@param arr Inputarray
@param idx0 Thefirst zero-based component of the element index
//傳回值類型:
typedefstructCvScalar{
double val[4];
}
           

變換前:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

變換後:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

灰階拉伸

根據目前灰階值所處的區間進行相應的變換

for (int i = 0;i < src->height; i++){
     for (int j = 0; j < src->width; j++){
         CvScalar s =cvGet2D(src, i, j);
         if(s.val[0] < x1)
              s.val[0] = y1 / x1*s.val[0];
         elseif (s.val[0] <= x2)
              s.val[0] = (y2 - y1) / (x2 -x1)*(s.val[0] - x1) + y1;
         else
              s.val[0] = (255 - y2) / (255 -x2)*(s.val[0] - x2) + y2;
         cvSet2D(dst, i, j, s);
     }
}
           

變換前:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

變換後:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

灰階直方圖

将灰階分為256個離散的值進行統計,存放在table數組中

for (int i = 0;i < src->height; i++){
     for (int j = 0; j < src->width; j++){
         CvScalar s =cvGet2D(src, i, j);
         table[(int)s.val[0]]++;
     }
}

//找出灰階出現次數的最大值,以對直方圖進行縮放
for (int i = 0;i < 256; i++)
     if (table[i]> max)max = table[i];

//建立直方圖:
Mat histgram(256, 256, CV_8U, Scalar(255));

//構造函數說明:
/** @overload
@param rows Numberof rows in a 2D array.
@param cols Numberof columns in a 2D array.
@param type Arraytype. Use CV_8UC1...CV_64FC4 to create 1-4 channel matrices, orCV_8UC(n)...CV_64FC(n) to create multi-channel (up toCV_CN_MAX channels) matrices.
@param s An optionalvalue to initialize each matrix element with. To set all the matrix elements tothe particular value after the construction, use theassignment operator
Mat::operator=(constScalar& value) .
*/
Mat(introws, intcols, inttype, constScalar& s);//s是所有像素的初始化值

//繪制直方圖:在指定的範圍内畫線,線的長度為指定會的像素個數,并且縮放到255之間
for (int i =range[0]; i <= range[1]; i++)
     line(histgram, Point(i,255), Point(i, (255 - table[i]*255/max)), Scalar(0));
           

直方圖:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

直方圖均衡

計算累計直方圖并取整确定映射關系:

for (int i = 1;i < 256; i++){
     s_table[i%2] = s_table[(i - 1)%2] + (float)table[i] / sum;
     new_table[i] = (int)(s_table[i%2]* 255 + 0.5);
}
           

用新值繪制新圖

均衡前:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

均衡後:

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)

源碼:

// opencv1.cpp: 定義控制台應用程式的入口點。
//

#include "stdafx.h"
#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <cv.h>
//#include <highgui.h>
#include <cxcore.h>
#include <cvaux.h>
#include <stdlib.h>
#include <imgproc.hpp>

using namespace cv;

int main()
{
	IplImage *src;
	src = cvLoadImage("pout.bmp", 1);//原圖
	IplImage *dst = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
	
	
	std::cout << "灰階線性變換..."<<std::endl;
	double fa = 1.0, fb = 0.0;
	while (fa >= 0)
	{
		for (int i = 0; i < src->height; i++)
		{
			for (int j = 0; j < src->width; j++)
			{
				CvScalar s = cvGet2D(src, i, j);
				s.val[0] = fa * s.val[0] + fb;
				cvSet2D(dst, i, j, s);
			}
		}
		cvNamedWindow("Image", 1);//建立視窗
		cvShowImage("Image", dst);//顯示圖像
		cvWaitKey(0); //等待按鍵
		cvDestroyWindow("Image");//銷毀視窗

		std::cin >> fa >> fb; 
	}

	std::cout << "灰階拉伸..."<<std::endl;
	double x1 = 0.0, y1 = 0.0, x2 = 1.0, y2 = 1.0;
	while (x1 >= 0)
	{
		for (int i = 0; i < src->height; i++)
		{
			for (int j = 0; j < src->width; j++)
			{
				CvScalar s = cvGet2D(src, i, j);
				if (s.val[0] < x1)
				{
					s.val[0] = y1 / x1*s.val[0];
				}
				else if (s.val[0] <= x2)
				{
					s.val[0] = (y2 - y1) / (x2 - x1)*(s.val[0] - x1) + y1;
				}
				else
				{
					s.val[0] = (255 - y2) / (255 - x2)*(s.val[0] - x2) + y2;
				}
				cvSet2D(dst, i, j, s);
			}
		}
		cvNamedWindow("Image", 1);//建立視窗
		cvShowImage("Image", dst);//顯示圖像
		cvWaitKey(0); //等待按鍵
		cvDestroyWindow("Image");//銷毀視窗

		std::cin >> x1 >> y1 >> x2 >> y2;
	}
	

	std::cout << "灰階直方圖..." << std::endl;

	int table[256] = { 0 };
	int range[] = { 0, 255 };
	std::cin >> range[0] >> range[1];
	for (int i = 0; i < src->height; i++)
	{
		for (int j = 0; j < src->width; j++)
		{
			CvScalar s = cvGet2D(src, i, j);
			table[(int)s.val[0]]++;
		}
	}
	double max = 0;
	int sum = 0;
	for (int i = 0; i < 256; i++)
	{
		sum += table[i];
		if (table[i] > max)max = table[i];
		//std::cout << table[i] << std:: endl;
	}
	Mat histgram(256, 256, CV_8U, Scalar(255));
	for (int i = range[0]; i <= range[1]; i++)
	{
		line(histgram, Point(i, 255), Point(i, (255 - table[i]*255/max)), Scalar(0));
	}
	namedWindow("histgram");
	imshow("histgram", histgram);
	waitKey(0);


	std::cout << "灰階均衡直方圖..." << std::endl;
	int new_table[256] = { 0 };
	float s_table[2] = { (float)table[0]/sum };
	for (int i = 1; i < 256; i++)
	{
		s_table[i%2] = s_table[(i - 1)%2] + (float)table[i] / sum;
		new_table[i] = (int)(s_table[i%2] * 255 + 0.5);
	}
	for (int i = 0; i < src->height; i++)
	{
		for (int j = 0; j < src->width; j++)
		{
			CvScalar s = cvGet2D(src, i, j);
			s.val[0] =new_table[(int)s.val[0]];
			cvSet2D(dst, i, j, s);
		}
	}


	cvNamedWindow("Image", 1);//建立視窗
	cvShowImage("Image", dst);//顯示圖像
	cvWaitKey(0); //等待按鍵
	cvDestroyWindow("Image");//銷毀視窗


	cvReleaseImage(&dst); //釋放圖像
}

           

原圖:(原來是bmp格式的,但是不能上傳,改成png格式了,分辨率都是256X256的)

opencv——圖像的灰階處理(線性變換/拉伸/直方圖/均衡化)