opencv學習之------遍歷圖像和鄰域操作

在圖像處理中,對當前位置像素的相鄰像素計算新的像素值是很常見的操作,當鄰域包括圖像的前幾行和下幾行時,你就需要同時掃描圖像的若干行。下面這個例子是對圖像進行銳化,它是基於拉普拉斯算子的。衆所周知,將一幅圖像減去它經過拉普拉斯濾波之後的圖像,這幅圖像的邊緣部分得到放大,即細節部分得到銳化,這個銳化的算子計算方式如下:

Sharpened_pixel=5*current-left-right-up-down;

其中left是代表當前像素左邊緊挨着它的像素,up代表在當前像素上邊緊挨着它的像素,以此類推。

實現方法如下:

void sharpend(const Mat& image, Mat& result)
{  //如有必要則分配圖像
       result.create(image.size(), image.type());
       for (int j = 1; j < image.rows-1; j++)
       { // 處理除了第一行和最後一行之外的所有行
              const uchar* previous = image.ptr<const uchar>(j - 1); //上一行
              const uchar* current = image.ptr<const uchar>(j); // 當前行
              const uchar* next = image.ptr<const uchar>(j + 1); //下一行
              uchar* output = result.ptr<uchar>(j); //輸出行
              for (int i = 1* image.channels(); i < (image.cols-1)*image.channels(); i++)
              {
                     output[i] = cv::saturate_cast<uchar>
                                (5 * current[i] - previous[i]-current[i-3]-current[i+3]-next[i]);
              }
       }  //將未處理的圖像設置爲0
       result.row(0).setTo(cv::Scalar(0,0,0));
       result.row(result.rows-1).setTo(cv::Scalar(0,0,0));
       result.col(0).setTo(cv::Scalar(0,0,0));
       result.col(result.cols - 1).setTo(cv::Scalar(0,0,0));
}
其中模板函數cv::saturate_cast用來對計算結果進行截斷;cv::Scalar(0,0,0)指定像素的三個通道的目標值

程序代碼如下:

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>

using namespace cv;
using namespace std;

void Sharpen(const Mat& image, Mat& ret);
void sharpenByFilter2D(const Mat& image, Mat& ret);

int main()
{
	Mat image;
	image = imread("8.jpg");
	if (!image.data)
	{
		return -1;
	}
	Mat copy;
	image.copyTo(copy);

	//filter2D()
	namedWindow("before");
	imshow("before", image);

	namedWindow("Sharpen");   //銳化之後的圖像
	Sharpen(image, image);
	imshow("Sharpen", image);

	namedWindow("sharpenByFilter2D");
	sharpenByFilter2D(copy, copy);  //使用cv::filter2D 進行圖像濾波,加過圖像濾波後的圖像
	imshow("sharpenByFilter2D", copy);

	cvWaitKey(-1);
	destroyAllWindows();
	return 0;
}

// 銳化算子公式: sharpened_pixel = 5 * current - left - right - up - down;
void Sharpen(const Mat& image, Mat& ret)
{
	CV_Assert(image.depth() == CV_8U); // accept only uchar images
	ret.create(image.size(), image.type()); // 保證和原圖像素等一樣大小

	const int nChannels = image.channels();

	// 除了第一行和最後一行,因爲其鄰域不完整
	for (int j = 1; j < image.rows - 1; ++j)
	{
		const uchar* pre = image.ptr<uchar>(j - 1);
		const uchar* cur = image.ptr<uchar>(j);
		const uchar* next = image.ptr<uchar>(j + 1);
		uchar* output = ret.ptr<uchar>(j);
		// 除了第一列和最後一列,因爲其鄰域不完整
		for (int i = nChannels; i < nChannels * (image.cols - 1); ++i)
		{
			// saturate_cast<uchr>用於確保該值在0-255之間
			*output++ = saturate_cast<uchar>(5 * cur[i] - cur[i - nChannels]
				- cur[i + nChannels] - pre[i] - next[i]);
		}

	}
	// 將未處理的像素點簡單的設置爲0值
	if (nChannels == 1)
	{
		ret.row(0).setTo(Scalar(0));
		ret.row(ret.rows - 1).setTo(Scalar(0));
		ret.col(0).setTo(Scalar(0));
		ret.col(ret.cols - 1).setTo(Scalar(0));
	}
	else if (nChannels == 3)
	{
		ret.row(0).setTo(Scalar(0, 0, 0));
		ret.row(ret.rows - 1).setTo(Scalar(0, 0, 0));
		ret.col(0).setTo(Scalar(0, 0, 0));
		ret.col(ret.cols - 1).setTo(Scalar(0, 0, 0));
	}
}


void sharpenByFilter2D(const Mat& image, Mat& ret)
{
	// 定義一個圖像濾波器(核),以使用cv::filter2D 進行圖像濾波
	Mat kern = (Mat_<char>(3, 3) << 0, -1, 0,
		-1, 5, -1,
		0, -1, 0);

	filter2D(image, ret, image.depth(), kern);
}

opencv定義了一個特殊的函數來完成濾波處理:cv::filter2D。在使用它之前,必須先以矩陣的形式定義一個核,之後以一幅圖像和這個核爲參數調用此函數,函數返回濾波後的圖像。利用這個函數,我們可以很簡單的重寫圖像銳化函數。

運行結果如下:

原始圖像:

圖像銳化處理後如下:

對圖像進行濾波處理後如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章