1. 程式人生 > >再論影象拉伸操作

再論影象拉伸操作

在前一篇文章《利用OpenMP加速拉伸影象操作》中,我介紹瞭如何利用自己寫的PerspectiveTransform類來拉伸影象。但是我們在那篇博文的最後看到了,拉伸結果並不完美:圖中夾雜了一些黑線和黑點。這是因為拉伸操作方式不合理:遍歷源圖,找到每一個源影象素點對應的目標影象素點,加以賦值。但是對映不是一一對應的,有的目標圖的畫素點找不到源圖的對應,就成為黑點。

解決的辦法是反向對映,遍歷目標圖的所有畫素點,然後對映到源圖上。把源影象素點的值賦給目標圖。

實踐這個想法有1個關鍵點:反向對映矩陣由原矩陣通過buildAdjoint()函式獲取。為此,我給PerspectiveTransform類添加了新的方法pntInvProjection()

/*反向變換,遍歷目標圖的所有畫素,獲取其在源圖的對應點畫素值*/
void PerspectiveTransform::pntInvProjection(unsigned char *pSrc, int iSrcWidth, int iSrcHeight,
										 unsigned char * pDst, int iDstWidth, int iDstHeight)
{
	PerspectiveTransform trans = buildAdjoint();
	for(int iX = 0; iX < iDstWidth; iX++)
	{
		for(int iY = 0; iY < iDstHeight; iY++)
		{
			float denominator = trans.a13 * iX + trans.a23 * iY + trans.a33;
			int iSrcX = (trans.a11 * iX + trans.a21 * iY + trans.a31) / denominator;
			int iSrcY = (trans.a12 * iX + trans.a22 * iY + trans.a32) / denominator;

			if(iSrcX >= 0 && iSrcX < iSrcWidth && iSrcY >= 0 && iSrcY < iSrcHeight)
			{
				pDst[iX + iY * iDstWidth] = pSrc[iSrcX + iSrcWidth * iSrcY];
			}
		}
	}
}

在main函式裡用pntInvProjection()取代pntProjection()。
#include "Perspective.h"
#include <opencv2/opencv.hpp>
#include <ctime>
#include <iostream>
#include <Windows.h>
#include <WinBase.h>


#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_core249d.lib")  
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_imgproc249d.lib")  
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_highgui249d.lib")  
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_features2d249d.lib")   
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_contrib249d.lib")  
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_legacy249d.lib")  

using namespace cv;
using namespace std;


int main()
{
	//SYSTEMTIME start, end;
	Mat img=imread("E:\\hehe.png");
	
	int img_height = img.rows;
	int img_width = img.cols;
	Mat img_trans = Mat::zeros(img_height,img_width,CV_8UC1);
	PerspectiveTransform tansform = PerspectiveTransform::quadrilateralToQuadrilateral
		(
		/*前面的8個座標是源圖的位置*/
		0,0,
		img_width-1,0,
		0,img_height-1,
		img_width-1,img_height-1,

		/*後面8個座標是目標圖的位置*/
		0,0, // top left
		670,200, // top right
		0,300,// bottom left
		350,440
		);

	unsigned char *p1 = img.ptr<unsigned char>(0);
	unsigned char *p2 = new unsigned char[img_width * img_height];

	for(int i = 0; i < img_width; i++)
	{
		for(int j =0; j < img_height; j++)
		{
			p2[j * img_width + i] = p1[j * img_width * 3 + i * 3];
		}
	}

	/*tansform.pntProjection(p2, img_width, img_height,
										 img_trans.ptr<unsigned char>(0), img_width, img_height);*/
	
	tansform.pntInvProjection(p2, img_width, img_height,
										 img_trans.ptr<unsigned char>(0), img_width, img_height);

	std::cin.get();
	imwrite("E:\\trans.png",img_trans);
	return 0;
}

效果: