激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++ OpenCV實現圖像雙三次插值算法詳解

C++ OpenCV實現圖像雙三次插值算法詳解

2022-03-08 15:26怎么今天你又不開心了呢 C/C++

圖像雙三次插值的原理,就是目標圖像的每一個像素都是由原圖上相對應點周圍的4x4=16個像素經過加權之后再相加得到的。本文主要介紹了通過C++ OpenCV實現圖像雙三次插值算法,需要的可以參考一下

前言

近期在學習一些傳統的圖像處理算法,比如傳統的圖像插值算法等。傳統的圖像插值算法包括鄰近插值法、雙線性插值法和雙三次插值法,其中鄰近插值法和雙線性插值法在網上都有很詳細的介紹以及用c++編寫的代碼。但是,網上關于雙三次插值法的原理介紹雖然很多,也有對應的代碼,但是大多都不是很詳細。因此基于自己對原理的理解,自己編寫了圖像雙三次插值算法的c++ opencv代碼,在這里記錄一下。

 

一、圖像雙三次插值算法原理

首先是原理部分。圖像雙三次插值的原理,就是目標圖像的每一個像素都是由原圖上相對應點周圍的4x4=16個像素經過加權之后再相加得到的。這里的加權用到的就是三次函數,這也是圖像雙三次插值算法名稱的由來(個人猜測)。用到的三次函數如下圖所示:

C++ OpenCV實現圖像雙三次插值算法詳解

最關鍵的問題是,這個三次函數的輸入和輸出分別代表啥。簡單來說輸入就是原圖對應點周圍相對于這點的4x4大小區域的坐標值,大小在0~2之間,輸出就是這些點橫坐標或者縱坐標的權重。4個橫坐標、4個縱坐標,對應相乘就是4x4大小的權重矩陣,然后使用此權重矩陣對原圖相對應的區域進行相乘并相加就可以得到目標圖點的像素。

下圖可以幫助大家更好地理解

C++ OpenCV實現圖像雙三次插值算法詳解

C++ OpenCV實現圖像雙三次插值算法詳解

首先,u和v是什么呢?舉一個例子,對于一幅100x100的灰度圖像,要將其放大到500x500,那么其縮放因子sx=500/100=5,sy=500/100=5。現在目標圖像是500x500,需要用原圖的100x100個像素值來填滿這500x500個空,根據src_x=i/sx和src_y=j/sy可以得到目標像素坐標(i,j)所對應的原圖像素坐標(src_x, src_y),這個src_x和src_y的小數部分就是上圖中的u和v。

理解了u和v,就可以利用u和v來計算雙三次插值算法的權重了。上面說了三次函數的輸入是原圖對應點周圍相對于這點的4x4大小區域的坐標值,對于上面這幅圖而言,橫坐標有四個輸入,分別是1+u,u,1-u,2-u;縱坐標也有四個輸入,分別是1+v,v,1-v,2-v,根據三次函數算出權重之后兩兩相乘就是對應的4x4大小的權重矩陣。

知道了怎么求權重矩陣之后,就可以遍歷整幅圖像進行插值了。下面是基于自己對原理的理解編寫的c++ opencv代碼,代碼沒有做優化,但是能夠讓大家直觀地理解圖像雙三次插值算法。

 

二、C++ OpenCV代碼

1.計算權重矩陣

前面說了權重矩陣就是橫坐標的4個輸出和縱坐標的4個輸出相乘,因此只需要求出橫坐標和縱坐標相對應的8個輸出值就行了。

代碼如下:

std::vector<double> getWeight(double c, double a = 0.5)
{
	//c就是u和v,橫坐標和縱坐標的輸出計算方式一樣
	std::vector<double> temp(4);
	temp[0] = 1 + c; temp[1] = c; 
	temp[2] = 1 - c; temp[3] = 2 - c;
	
	//y(x) = (a+2)|x|*|x|*|x| - (a+3)|x|*|x| + 1   |x|<=1
	//y(x) = a|x|*|x|*|x| - 5a|x|*|x| + 8a|x| - 4a  1<|x|<2
	std::vector<double> weight(4);
	weight[0] = (a * pow(abs(temp[0]), 3) - 5 * a * pow(abs(temp[0]), 2) + 8 * a * abs(temp[0]) - 4 * a);
	weight[1] = (a + 2) * pow(abs(temp[1]), 3) - (a + 3) * pow(abs(temp[1]), 2) + 1;
	weight[2] = (a + 2) * pow(abs(temp[2]), 3) - (a + 3) * pow(abs(temp[2]), 2) + 1;
	weight[3] = (a * pow(abs(temp[3]), 3) - 5 * a * pow(abs(temp[3]), 2) + 8 * a * abs(temp[3]) - 4 * a);

	return weight;
}

2.遍歷插值

代碼如下:

void bicubic(cv::Mat& src, cv::Mat& dst, int dst_rows, int dst_cols)
{
	dst.create(dst_rows, dst_cols, src.type());
	double sy = static_cast<double>(dst_rows) / static_cast<double>(src.rows);
	double sx = static_cast<double>(dst_cols) / static_cast<double>(src.cols);
	cv::Mat border;
	cv::copyMakeBorder(src, border, 1, 1, 1, 1, cv::BORDER_REFLECT_101);

	//處理灰度圖
	if (src.channels() == 1)
	{
		for (int i = 1; i < dst_rows + 1; ++i)
		{
			int src_y = (i + 0.5) / sy - 0.5; //做了幾何中心對齊
			if (src_y < 0) src_y = 0;
			if (src_y > src.rows - 1) src_y = src.rows - 1;
			src_y += 1;
			//目標圖像點坐標對應原圖點坐標的4個縱坐標
			int i1 = std::floor(src_y);
			int i2 = std::ceil(src_y);
			int i0 = i1 - 1;
			int i3 = i2 + 1;
			double u = src_y - static_cast<int64>(i1);
			std::vector<double> weight_x = getWeight(u);

			for (int j = 1; j < dst_cols + 1; ++j)
			{
				int src_x = (j + 0.5) / sy - 0.5;
				if (src_x < 0) src_x = 0;
				if (src_x > src.rows - 1) src_x = src.rows - 1;
				src_x += 1;
				//目標圖像點坐標對應原圖點坐標的4個橫坐標
				int j1 = std::floor(src_x);
				int j2 = std::ceil(src_x);
				int j0 = j1 - 1;
				int j3 = j2 + 1;
				double v = src_x - static_cast<int64>(j1);
				std::vector<double> weight_y = getWeight(v);

				//目標點像素對應原圖點像素周圍4x4區域的加權計算(插值)
				double pix = weight_x[0] * weight_y[0] * border.at<uchar>(i0, j0) + weight_x[1] * weight_y[0] * border.at<uchar>(i0, j1)
					+ weight_x[2] * weight_y[0] * border.at<uchar>(i0, j2) + weight_x[3] * weight_y[0] * border.at<uchar>(i0, j3)
					+ weight_x[0] * weight_y[1] * border.at<uchar>(i1, j0) + weight_x[1] * weight_y[1] * border.at<uchar>(i1, j1)
					+ weight_x[2] * weight_y[1] * border.at<uchar>(i1, j2) + weight_x[3] * weight_y[1] * border.at<uchar>(i1, j3)
					+ weight_x[0] * weight_y[2] * border.at<uchar>(i2, j0) + weight_x[1] * weight_y[2] * border.at<uchar>(i2, j1)
					+ weight_x[2] * weight_y[2] * border.at<uchar>(i2, j2) + weight_x[3] * weight_y[2] * border.at<uchar>(i2, j3)
					+ weight_x[0] * weight_y[3] * border.at<uchar>(i3, j0) + weight_x[1] * weight_y[3] * border.at<uchar>(i3, j1)
					+ weight_x[2] * weight_y[3] * border.at<uchar>(i3, j2) + weight_x[3] * weight_y[3] * border.at<uchar>(i3, j3);
				if (pix < 0) pix = 0;
				if (pix > 255)pix = 255;

				dst.at<uchar>(i - 1, j - 1) = static_cast<uchar>(pix);
			}
		}
	}
	//處理彩色圖像
	else if (src.channels() == 3)
	{
		for (int i = 1; i < dst_rows + 1; ++i)
		{
			int src_y = (i + 0.5) / sy - 0.5;
			if (src_y < 0) src_y = 0;
			if (src_y > src.rows - 1) src_y = src.rows - 1;
			src_y += 1;
			int i1 = std::floor(src_y);
			int i2 = std::ceil(src_y);
			int i0 = i1 - 1;
			int i3 = i2 + 1;
			double u = src_y - static_cast<int64>(i1);
			std::vector<double> weight_y = getWeight(u);

			for (int j = 1; j < dst_cols + 1; ++j)
			{
				int src_x = (j + 0.5) / sy - 0.5;
				if (src_x < 0) src_x = 0;
				if (src_x > src.rows - 1) src_x = src.rows - 1;
				src_x += 1;
				int j1 = std::floor(src_x);
				int j2 = std::ceil(src_x);
				int j0 = j1 - 1;
				int j3 = j2 + 1;
				double v = src_x - static_cast<int64>(j1);
				std::vector<double> weight_x = getWeight(v);

				cv::Vec3b pix;

				pix[0] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[0] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[0]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[0] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[0]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[0] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[0]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[0] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[0]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[0] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[0]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[0] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[0]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[0] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[0]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[0] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[0];
				pix[1] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[1] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[1]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[1] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[1]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[1] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[1]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[1] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[1]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[1] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[1]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[1] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[1]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[1] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[1]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[1] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[1];
				pix[2] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[2] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[2]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[2] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[2]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[2] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[2]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[2] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[2]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[2] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[2]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[2] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[2]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[2] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[2]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[2] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[2];

				for (int i = 0; i < src.channels(); ++i)
				{
					if (pix[i] < 0) pix = 0;
					if (pix[i] > 255)pix = 255;
				}
				dst.at<cv::Vec3b>(i - 1, j - 1) = static_cast<cv::Vec3b>(pix);
			}
		}	
	}	
}

3. 測試及結果

int main()
{
	cv::Mat src = cv::imread("C:\\Users\\Echo\\Pictures\\Saved Pictures\\bilateral.png");
	cv::Mat dst;
	bicubic(src, dst, 309/0.5, 338/0.5);
	cv::imshow("gray", dst);
	cv::imshow("src", src);
	cv::waitKey(0);
}

彩色圖像(放大兩倍)

C++ OpenCV實現圖像雙三次插值算法詳解

C++ OpenCV實現圖像雙三次插值算法詳解

以上就是C++ OpenCV實現圖像雙三次插值算法詳解的詳細內容,更多關于C++ OpenCV 圖像雙三次插值算法的資料請關注服務器之家其它相關文章!

原文鏈接:https://blog.csdn.net/weixin_44509043/article/details/121660853

延伸 · 閱讀

精彩推薦
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
主站蜘蛛池模板: 国产成人在线免费视频 | av在线免费播放网站 | 久久久精品视频网站 | 午夜男人在线观看 | 国产毛毛片一区二区三区四区 | 凹凸成人精品亚洲精品密奴 | 国产成人网 | 成人在线精品视频 | 免费大香伊蕉在人线国产 | 日日操夜 | 免费看成年人视频在线 | 成人午夜看片 | 长泽雅美av| 国产一区二区在线免费播放 | 成年人观看免费视频 | 一级一级一级一级毛片 | 久久精品免费国产 | 爱视频福利 | 91成| 91免费无限观看 | 午夜久久电影 | 一级毛片免费在线 | 在线播放免费视频 | 午夜视频免费在线观看 | 午夜国产在线 | 精品久久久久久久 | 91看片淫黄大片欧美看国产片 | 怦然心动50免费完整版 | 久久精品视频在线免费观看 | 久久久久亚洲a | 视频一区二区三区在线播放 | 一本到免费视频 | 久久免费视频一区二区三区 | 色午夜日本| 特级黄一级播放 | 国产精品久久久久网站 | 黄色高清免费 | 亚洲国产网址 | 成人一区二区在线观看视频 | av国产片| 成人毛片视频在线观看 |