拉伸,收縮,扭曲和旋轉
均勻調整
最簡單的調整大小的方法,就是調用cv::resize()函數,函數原型如下:
cv::resize(
cv::InputArray src, 輸入圖像
cv::OutputArray dst, 輸出圖像
cv::Size dsize, 圖像變換後的大小
double fx = 0, 當dsize = (0,0)時,fx爲x軸比例因子
double fy = 0,
int interpolation = CV::INTER_LINEAR 插值方法,默認爲線性插值
);
cv::resize()函數的插值選項:
INTER_NEAREST 最近鄰插值
INTER_LINEAR 雙線性插值
INTER_AREA 像素區域重採樣
INTER_CUBIC 雙三次插值
INTER_LANCZOS4 插值(超過8*8個鄰域)
這個函數有兩個使用方法
- 使用前三個參數,dsize參數就是你想讓圖像變成的大小
- 使用前兩個和fx,fy參數,將dsize換設爲(0,0),fx與fy爲各軸的比例因子
下面看個程序:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src,dst1,dst2;
src = imread("1.jpg", 1);
imshow("原圖", src);
Size2i sz(200, 150); //設置大小
resize(src, dst1, sz);
resize(src, dst2, Size(0, 0), 2, 2);
imshow("變換1", dst1);
imshow("變換2", dst2);
waitKey(0);
return 0;
}
仿射變換與透視變換
雖然目前,我不知道這兩個變換在哪些方面會有妙用與奇效,但既然有這個功能,就先整理一下。目前就知道,當你知道多個圖像是同一個圖像的不同角度的視圖時,可能需要計算不同試圖相關的實際變換。
對於平面圖像,應用23矩陣進行變換,稱爲“仿射變換”,而基於33矩陣進行變換,稱爲“透視變換”。仿射變換可以將矩形轉換爲平行四邊形,而透視變換提供更多的靈活性,可以將矩形變換爲任意四邊形。
首先看仿射變換
函數原型:
warpAffine(
InputArray src, 輸入圖像
OutputArray dst, 輸出圖像
InputArray M, 仿射計算矩陣
Size dsize, 輸出圖像大小
int flags = INIET_LINEAR, 插值方法
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar()
);
其中比較難搞的就是第三個參數仿射計算矩陣,這個矩陣需要我們自己計算,但opencv提供了計算該矩陣的函數:
getAffineTransform(
const Point2f* src,
const Point2f* dst
);
下面提供一下對一幅圖片進行仿射操作的常規步驟:
- 首先定義兩組二維點數組,數組長度爲3
- 定義2*3大小的仿射矩陣
- 設置源圖像和目標圖像上的三組點以計算仿射變換
- 求得仿射變換矩陣
- 對源圖像應用剛剛求得的仿射變換
下面貼代碼來看一看:
int main()
{
//【1】參數準備
Mat srcImage, dstImage_warp, dst2;
srcImage = imread("2.jpg", 1);
if (!srcImage.data) { printf("讀取圖片錯誤,請確定目錄下是否有imread函數指定的圖片存在~! \n"); return false; }
imshow("原圖", srcImage);
//定義兩組點,代表兩個三角形
Point2f srcTriangle[3];
Point2f dstTriangle[3];
//定義Mat類仿射矩陣
Mat warpMat(2, 3, CV_32FC1);
//【2】設置目標圖像的大小和類型與源圖像一致
dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());
//【3】設置源圖像和目標圖像上的三組點以計算仿射變換
srcTriangle[0] = Point2f(0, 0);
srcTriangle[1] = Point2f(static_cast<float>(srcImage.cols - 1), 0);
srcTriangle[2] = Point2f(0, static_cast<float>(srcImage.rows - 1));
dstTriangle[0] = Point2f(static_cast<float>(srcImage.cols*0.0), static_cast<float>(srcImage.rows*0.33));
dstTriangle[1] = Point2f(static_cast<float>(srcImage.cols*0.65), static_cast<float>(srcImage.rows*0.35));
dstTriangle[2] = Point2f(static_cast<float>(srcImage.cols*0.15), static_cast<float>(srcImage.rows*0.6));
//【4】求得仿射變換
warpMat = getAffineTransform(srcTriangle, dstTriangle);
//【5】對源圖像應用剛剛求得的仿射變換
warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size());
imshow("仿射變換", dstImage_warp);
waitKey(0);
return 0;
}
對於透視變換,有着類似的操作,這裏就不多說了,就貼兩張函數截圖好了。
WarpPerspective()透視變換函數:
圖像修復
圖像修復是涉及一個cv::inpaint()函數,函數原型:
cv::inpaint(
InputArray src, 輸入圖像
InputArray inpaintMast,圖像醃膜
OutputArray dst, 輸出圖像
double inpaintRadius, 每個已渲染像素周圍的區域大小
int flags 圖像修復方法INPAINT_NS INPAINT_TELEA
);
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
#define WINDOW_NAME0 "【原始圖參考】" //爲窗口標題定義的宏
#define WINDOW_NAME1 "【原始圖】" //爲窗口標題定義的宏
#define WINDOW_NAME2 "【修補後的效果圖】" //爲窗口標題定義的宏
//-----------------------------------【全局變量聲明部分】--------------------------------------
// 描述:全局變量聲明
//-----------------------------------------------------------------------------------------------
Mat srcImage0, srcImage1, inpaintMask;
Point previousPoint(-1, -1);//原來的點座標
//-----------------------------------【ShowHelpText( )函數】----------------------------------
// 描述:輸出一些幫助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//輸出歡迎信息和OpenCV版本
printf("\n\n\t\t\t非常感謝購買《OpenCV3編程入門》一書!\n");
printf("\n\n\t\t\t此爲本書OpenCV3版的第78個配套示例程序\n");
printf("\n\n\t\t\t 當前使用的OpenCV版本爲:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
//輸出一些幫助信息
printf("\n\n\n\t歡迎來到【圖像修復】示例程序~\n");
printf("\n\t請在進行圖像修復操作之前,在【原始圖】窗口中進行適量的繪製"
"\n\n\t按鍵操作說明: \n\n"
"\t\t【鼠標左鍵】-在圖像上繪製白色線條\n\n"
"\t\t鍵盤按鍵【ESC】- 退出程序\n\n"
"\t\t鍵盤按鍵【1】或【SPACE】-進行圖像修復操作 \n\n");
}
//-----------------------------------【On_Mouse( )函數】--------------------------------
// 描述:響應鼠標消息的回調函數
//----------------------------------------------------------------------------------------------
static void On_Mouse(int event, int x, int y, int flags, void*)
{
//鼠標左鍵彈起消息
if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
previousPoint = Point(-1, -1);
//鼠標左鍵按下消息
else if (event == EVENT_LBUTTONDOWN)
previousPoint = Point(x, y);
//鼠標按下並移動,進行繪製
else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
{
Point pt(x, y);
if (previousPoint.x < 0)
previousPoint = pt;
//繪製白色線條
line(inpaintMask, previousPoint, pt, Scalar::all(255), 5, 8, 0);
line(srcImage1, previousPoint, pt, Scalar::all(255), 5, 8, 0);
previousPoint = pt;
imshow(WINDOW_NAME1, srcImage1);
}
}
//--------------------------------------【main( )函數】-----------------------------------------
// 描述:控制檯應用程序的入口函數,我們的程序從這裏開始執行
//-----------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
//改變console字體顏色
system("color 2F");
//顯示幫助文字
ShowHelpText();
//載入原始圖並進行掩膜的初始化
Mat srcImage = imread("1.jpg", -1);
if (!srcImage.data) { printf("讀取圖片錯誤,請確定目錄下是否有imread函數指定圖片存在~! \n"); return false; }
srcImage0 = srcImage.clone();
srcImage1 = srcImage.clone();
inpaintMask = Mat::zeros(srcImage1.size(), CV_8U);
//顯示原始圖參考
imshow(WINDOW_NAME0, srcImage0);
//顯示原始圖
imshow(WINDOW_NAME1, srcImage1);
//設置鼠標回調消息
setMouseCallback(WINDOW_NAME1, On_Mouse, 0);
//輪詢按鍵,根據不同的按鍵進行處理
while (1)
{
//獲取按鍵鍵值
char c = (char)waitKey();
//鍵值爲ESC,程序退出
if (c == 27)
break;
//鍵值爲2,恢復成原始圖像
if (c == '2')
{
inpaintMask = Scalar::all(0);
srcImage.copyTo(srcImage1);
imshow(WINDOW_NAME1, srcImage1);
}
//鍵值爲1或者空格,進行圖像修補操作
if (c == '1' || c == ' ')
{
Mat inpaintedImage;
inpaint(srcImage1, inpaintMask, inpaintedImage, 3, INPAINT_TELEA);
imshow(WINDOW_NAME2, inpaintedImage);
}
}
return 0;
}