最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ OpenCV實(shí)現(xiàn)圖像雙三次插值算法詳解

 更新時(shí)間:2021年12月02日 16:19:37   作者:怎么今天你又不開心了呢  
圖像雙三次插值的原理,就是目標(biāo)圖像的每一個(gè)像素都是由原圖上相對(duì)應(yīng)點(diǎn)周圍的4x4=16個(gè)像素經(jīng)過加權(quán)之后再相加得到的。本文主要介紹了通過C++ OpenCV實(shí)現(xiàn)圖像雙三次插值算法,需要的可以參考一下

前言

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

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

首先是原理部分。圖像雙三次插值的原理,就是目標(biāo)圖像的每一個(gè)像素都是由原圖上相對(duì)應(yīng)點(diǎn)周圍的4x4=16個(gè)像素經(jīng)過加權(quán)之后再相加得到的。這里的加權(quán)用到的就是三次函數(shù),這也是圖像雙三次插值算法名稱的由來(個(gè)人猜測(cè))。用到的三次函數(shù)如下圖所示:

最關(guān)鍵的問題是,這個(gè)三次函數(shù)的輸入和輸出分別代表啥。簡(jiǎn)單來說輸入就是原圖對(duì)應(yīng)點(diǎn)周圍相對(duì)于這點(diǎn)的4x4大小區(qū)域的坐標(biāo)值,大小在0~2之間,輸出就是這些點(diǎn)橫坐標(biāo)或者縱坐標(biāo)的權(quán)重。4個(gè)橫坐標(biāo)、4個(gè)縱坐標(biāo),對(duì)應(yīng)相乘就是4x4大小的權(quán)重矩陣,然后使用此權(quán)重矩陣對(duì)原圖相對(duì)應(yīng)的區(qū)域進(jìn)行相乘并相加就可以得到目標(biāo)圖點(diǎn)的像素。

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

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

理解了u和v,就可以利用u和v來計(jì)算雙三次插值算法的權(quán)重了。上面說了三次函數(shù)的輸入是原圖對(duì)應(yīng)點(diǎn)周圍相對(duì)于這點(diǎn)的4x4大小區(qū)域的坐標(biāo)值,對(duì)于上面這幅圖而言,橫坐標(biāo)有四個(gè)輸入,分別是1+u,u,1-u,2-u;縱坐標(biāo)也有四個(gè)輸入,分別是1+v,v,1-v,2-v,根據(jù)三次函數(shù)算出權(quán)重之后兩兩相乘就是對(duì)應(yīng)的4x4大小的權(quán)重矩陣。

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

二、C++ OpenCV代碼

1.計(jì)算權(quán)重矩陣

前面說了權(quán)重矩陣就是橫坐標(biāo)的4個(gè)輸出和縱坐標(biāo)的4個(gè)輸出相乘,因此只需要求出橫坐標(biāo)和縱坐標(biāo)相對(duì)應(yīng)的8個(gè)輸出值就行了。

代碼如下:

std::vector<double> getWeight(double c, double a = 0.5)
{
	//c就是u和v,橫坐標(biāo)和縱坐標(biāo)的輸出計(jì)算方式一樣
	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; //做了幾何中心對(duì)齊
			if (src_y < 0) src_y = 0;
			if (src_y > src.rows - 1) src_y = src.rows - 1;
			src_y += 1;
			//目標(biāo)圖像點(diǎn)坐標(biāo)對(duì)應(yīng)原圖點(diǎn)坐標(biāo)的4個(gè)縱坐標(biāo)
			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;
				//目標(biāo)圖像點(diǎn)坐標(biāo)對(duì)應(yīng)原圖點(diǎn)坐標(biāo)的4個(gè)橫坐標(biāo)
				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);

				//目標(biāo)點(diǎn)像素對(duì)應(yīng)原圖點(diǎn)像素周圍4x4區(qū)域的加權(quán)計(jì)算(插值)
				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. 測(cè)試及結(jié)果

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實(shí)現(xiàn)圖像雙三次插值算法詳解的詳細(xì)內(nèi)容,更多關(guān)于C++ OpenCV 圖像雙三次插值算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • c語言處理函數(shù)調(diào)用的方法

    c語言處理函數(shù)調(diào)用的方法

    函數(shù)就是一段封裝好的,可以重復(fù)使用的代碼,它使得我們的程序更加模塊化,不需要編寫大量重復(fù)的代碼。這篇文章主要介紹了c語言是如何處理函數(shù)調(diào)用的?需要的朋友可以參考下
    2021-11-11
  • socket多人聊天程序C語言版(二)

    socket多人聊天程序C語言版(二)

    這篇文章主要為大家詳細(xì)介紹了socket多人聊天程序C語言版第二篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

    詳解C++ 多態(tài)的實(shí)現(xiàn)及原理

    這篇文章主要介紹了C++ 多態(tài)的實(shí)現(xiàn)及原理,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • C和C++混合編程問題

    C和C++混合編程問題

    這篇文章主要介紹了C和C++混合編程問題,需要的朋友可以參考下
    2015-10-10
  • C++類和對(duì)象基礎(chǔ)詳解

    C++類和對(duì)象基礎(chǔ)詳解

    類是創(chuàng)建對(duì)象的模板,一個(gè)類可以創(chuàng)建多個(gè)對(duì)象,每個(gè)對(duì)象都是類類型的一個(gè)變量;創(chuàng)建對(duì)象的過程也叫類的實(shí)例化。每個(gè)對(duì)象都是類的一個(gè)具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)
    2021-08-08
  • C語言實(shí)現(xiàn)爆炸展開的掃雷詳解

    C語言實(shí)現(xiàn)爆炸展開的掃雷詳解

    windows自帶的游戲《掃雷》是陪伴了無數(shù)人的經(jīng)典游戲,本文將利用C語言實(shí)現(xiàn)這一經(jīng)典的游戲,文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下,這篇文章主要介紹了C語言實(shí)現(xiàn)爆炸展開的掃雷游戲
    2022-07-07
  • 深入淺析OpenCV?copyTo()函數(shù)

    深入淺析OpenCV?copyTo()函數(shù)

    在Mat矩陣類的成員函數(shù)中copyTo(roi , mask)函數(shù)是非常有用的一個(gè)函數(shù),尤其是后面的mask可以實(shí)現(xiàn)蒙版的功能,下面通過本文給大家介紹下OpenCV copyTo()函數(shù)的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2022-01-01
  • C++多線程編程和同步機(jī)制實(shí)例演示

    C++多線程編程和同步機(jī)制實(shí)例演示

    C++中的多線程編程和同步機(jī)制使得程序員可以利用計(jì)算機(jī)的多核心來提高程序的運(yùn)行效率和性能,本文將介紹多線程編程和同步機(jī)制的基本概念和使用方法
    2023-09-09
  • C++設(shè)計(jì)模式之工廠模式

    C++設(shè)計(jì)模式之工廠模式

    本文是C++設(shè)計(jì)模式系列文章的第一篇,主要給大家講述下工廠模式,非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下
    2016-05-05
  • Objective-C限制函數(shù)調(diào)用的頻率詳解

    Objective-C限制函數(shù)調(diào)用的頻率詳解

    這篇文章主要給大家介紹了關(guān)于Objective-C限制函數(shù)調(diào)用的頻率的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12

最新評(píng)論

霍城县| 上栗县| 齐齐哈尔市| 福建省| 莆田市| 普洱| 基隆市| 南投市| 那曲县| 从化市| 无锡市| 循化| 驻马店市| 天等县| 林甸县| 专栏| 万源市| 怀仁县| 松桃| 永州市| 虎林市| 泗阳县| 林州市| 永昌县| 阳城县| 昔阳县| 新巴尔虎左旗| 游戏| 扬州市| 长海县| 迁安市| 黄平县| 彩票| 东海县| 仪征市| 哈尔滨市| 清远市| 图们市| 确山县| 额尔古纳市| 德惠市|