若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105633350
各位讀者,知識無窮而人力有窮,要麼改需求,要麼找專業人士,要麼自己研究
目錄
紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中...(點擊傳送門).
OpenCV開發專欄(點擊傳送門)
OpenCV開發筆記(四十五):紅胖子8分鐘帶你深入瞭解重映射(圖文並茂+淺顯易懂+程序源碼)
前言
紅胖子,來也!!!
本篇章講解重映射。
相關博客
圖像檢測中對圖像進行旋轉、鏡像等操作是可以對原尺寸進行操作的,有專門的旋轉、翻轉函數進行處理。
《OpenCV開發筆記(八):OpenCV常用操作之計時、縮放、旋轉、鏡像》
該文章中,也同樣實現了部分簡單重映射效果,使用的四個函數:
- 旋轉函數1:cv::transpose,直接對矩陣進行順時鐘旋轉90°
- 旋轉函數2:cv::rotate,三個枚舉可以旋轉90°,180°,270°
- 翻轉函數:cv::flip,xy軸翻轉
- 縮放函數:cv::resize,縮放
Demo
重映射
概述
重映射,按照與原圖一樣大小的尺寸,通過像素下標的序列號的矩陣進行映射得到結果,簡而言之,就是把一幅圖像中某位置的像素放置到另一個圖片指定位置的過程。
X軸旋轉/Y軸旋轉/XY軸旋轉原理示意圖
縮放1/2原理示意圖
傾斜45度示意圖
函數原型
void remap( InputArray src,
OutputArray dst,
InputArray map1,
InputArray map2,
int interpolation,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
- 參數一:InputArray類型的src,一般爲cv::Mat;
- 參數二:OutputArray類型的dst,目標圖像。它的大小與map1相同,類型與src相同。
- 參數三:InputArray類型的map1,它有兩種可能的表示對象:表示點(x,y)的第一個映射或者表示CV_16SC2 , CV_32FC1 或CV_32FC2類型的x值。
- 參數四:InputArray類型的map2,它也有兩種可能的表示對象,而且他是根據map1來確定表示哪種對象。若map1表示點(x,y)時,這個參數不代表任何值,否則,表示CV_16UC1 , CV_32FC1類型的y值(第二個值)。
- 參數五:int類型的interpolation,使用的插值方法;
- 參數六:int類型的borderMode,邊界處理方式;
- 參數七:Scalar類型的borderValue,重映射後,離羣點的背景,需要broderMode設置爲BORDER_CONSTRANT時纔有效。(離羣點:當圖片大小爲400x300,那麼對應的map1和map2範圍爲0~399、0~299,小於0或者大於299的則爲離散點,使用該顏色填充);
Demo源碼
void OpenCVManager::testRemap()
{
QString fileName1 = "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
cv::Mat srcMat = cv::imread(fileName1.toStdString());
cv::Mat dstMat;
int width = 400;
int height = 300;
cv::resize(srcMat, srcMat, cv::Size(width, height));
cv::String windowName = _windowTitle.toStdString();
cvui::init(windowName);
cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 4),
srcMat.type());
while(true)
{
windowMat = cv::Scalar(0, 0, 0);
cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);
cv::Mat mapX;
cv::Mat mapY;
// 第一種x翻轉
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>(col);
mapY.at<float>(row, col) = static_cast<float>(srcMat.rows - row - 1);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第二種y翻轉
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>(srcMat.cols - col - 1);
mapY.at<float>(row, col) = static_cast<float>(row);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
cv::Range(srcMat.cols * 1, srcMat.cols * 2));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第三種x,y翻轉
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>(srcMat.cols - col - 1);
mapY.at<float>(row, col) = static_cast<float>(srcMat.rows - row - 1);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
cv::Range(srcMat.cols * 1, srcMat.cols * 2));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第四種:右半邊拉伸一倍
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>(col / 2);
mapY.at<float>(row, col) = static_cast<float>(row);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第五種,縮小1/2,並顯示在中間,底色爲藍色
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
if(col < srcMat.cols / 4 || row < srcMat.rows / 4)
{
mapX.at<float>(row, col) = -1;
mapY.at<float>(row, col) = -1;
}else if(col >= srcMat.cols / 4 * 3 || row >= srcMat.rows / 4 * 3)
{
mapX.at<float>(row, col) = -1;
mapY.at<float>(row, col) = -1;
}else{
mapX.at<float>(row, col) = static_cast<float>((col - srcMat.cols / 4) * 2);
mapY.at<float>(row, col) = static_cast<float>((row - srcMat.rows / 4) * 2);
}
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 1, srcMat.cols * 2));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第六種,矩陣旋轉90度(輸出必須和輸入大小一樣,此時可以使用resize縮放至快高對調的比例)
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>(row);
mapY.at<float>(row, col) = static_cast<float>(col);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 第七種,順時針傾斜45°
{
mapX.create(srcMat.size(), CV_32FC1);
mapY.create(srcMat.size(), CV_32FC1);
for(int row = 0; row < srcMat.rows; row++)
{
for(int col = 0; col < srcMat.cols; col++)
{
mapX.at<float>(row, col) = static_cast<float>((col + (srcMat.cols * 2 - (srcMat.rows - row) - 1)) % srcMat.cols);
mapY.at<float>(row, col) = static_cast<float>(row);
}
}
dstMat.create(srcMat.size(), srcMat.type());
cv::remap(srcMat,
dstMat,
mapX,
mapY,
CV_INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(255, 0, 0));
mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
cv::Range(srcMat.cols * 1, srcMat.cols * 2));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 更新
cvui::update();
// 顯示
cv::imshow(windowName, windowMat);
// esc鍵退出
if(cv::waitKey(25) == 27)
{
break;
}
}
}
工程模板:對應版本號v1.40.0
對應版本號v1.40.0
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105633350