OpenCV圖像剪切的擴展和高級用法:任意裁剪,邊界擴充
【尊重原創,轉載請注明出處】http://blog.csdn.net/guyuealian/article/details/78113325 利用感興趣區域ROI和矩形類Rect,在OpenCV中可以很簡單的就實現圖像裁剪和剪切的功能,但剪切時常常會出現超出圖像邊界的區域的情況,對于超出圖像邊界的區域,我們必須進行特殊的處理,以避免出組數組越界的錯誤,如圖1所示的裁剪錯誤。cv::Mat src = cv::imread("D:\\OpencvTest\\1.jpg");//原始圖像是200*200
cv::Rect rect(-100, -100, 500, 500);
cv::Mat image = src(rect);//這時裁剪,必然出錯
圖1 對于特殊的要求,如,我們希望可以指定的顏色來填充,或者復制邊界的像素的填充,甚至想鏡像某個位置填充超出的邊界,應該怎么辦呢?OpenCV3中提供了一個圖像邊界的函數cv::copyMakeBorder(對應opencv2中的cvCopyMakeBorder)以及borderInterpolate,利用這個函數,可以間接實現這個功能。 copyMakeBorder函數的用法,請參考博客:http://blog.csdn.net/qianqing13579/article/details/42323397 注意:copyMakeBorder函數不能直接用于圖像裁剪,博客后面會貼出封裝好的ImageCropPadding()函數,方便親們調用函數原型:copyMakeBorder
void copyMakeBorder( const Mat& src, Mat& dst,int top, int bottom, int left, int right,int borderType, const Scalar& value=Scalar() );
函數功能:
用于擴充src圖像的邊緣,使得圖像變大變寬,該函數調用了cv::borderInterpolate函數
參數說明:
src,dst:原圖與目標圖像top,bottom,left,right分別表示在原圖四周擴充邊緣的大小borderType:擴充邊緣的類型,OpenCV中給出以下幾種方式
* BORDER_REPLICATE* BORDER_REFLECT* BORDER_REFLECT_101* BORDER_WRAP* BORDER_CONSTANT
說明如下:
Enumerator
| BORDER_CONSTANT? | iiiiii|abcdefgh|iiiiiii?with some specified?i(指定常數填充) |
| BORDER_REPLICATE? | aaaaaa|abcdefgh|hhhhhhh(復制邊緣像素填充) |
| BORDER_REFLECT? | fedcba|abcdefgh|hgfedcb(反射復制邊界像素) |
| BORDER_WRAP? | cdefgh|abcdefgh|abcdefg |
| BORDER_REFLECT_101? | gfedcb|abcdefgh|gfedcba(對稱填充,也就是以最邊緣像素為軸) |
| BORDER_TRANSPARENT? | uvwxyz|absdefgh|ijklmno |
| BORDER_REFLECT101? | same as BORDER_REFLECT_101 |
| BORDER_DEFAULT? | same as BORDER_REFLECT_101 |
| BORDER_ISOLATED? | do not look outside of ROI |
(1)BORDER_REPLICATE:復制法,也就是復制最邊緣像素。
如上圖,紅色區域為src的最邊界像素,藍色區域是擴充的邊界,我們將邊緣擴大了5個像素(right=5),藍色區域的寬度就是5,復制了5次紅色區域的值。
這種方式也就是OpenCV中的中值濾波medianBlur采用的邊界處理方式 (2)BORDER_REFLECT_101:對稱法,也就是以最邊緣像素為軸,對稱擴展。如下面的圖
綠色區域是src最邊界的像素,藍色區域是我們擴充的5個像素的擴充邊界,而紅色區域就是藍色區域在src的對稱部分。這種方式也是OpenCV邊界處理的默認方式(BORDER_DEFAULT=BORDER_REFLECT_101)
也是filter2D,blur,GaussianBlur,bilateralFilter的默認處理方式,所以這種方式在邊界處理中應用還是非常廣泛的
(3)BORDER_CONSTANT:常量法,可指定顏色填充常量法就是以一個常量像素值(由參數 value給定)填充擴充的邊界值,這種方式在仿射變換,透視變換中非常常見
如下圖:
這里使用了默認的value,黑色填充了邊界,所以紅色區域的擴充的5個像素寬的邊界是黑色的在copyMakeBorder的內部,調用了函數borderInterpolate
? 前面提到,copyMakeBorder函數只是進行圖像的簡單擴充而已,而我們需要的是在圖像裁剪時,對超過邊界區域實現顏色自動填充。這里實現了一個Demo,對于超出剪切的區域,用紅色(或其他)填充,這里貼出封裝好的ImageCropPadding()函數,方便親們調用下面#include "stdafx.h"
#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;cv::Mat ImageCropPadding(cv::Mat srcImage, cv::Rect rect)
{//cv::Mat srcImage = image.clone();int crop_x1 = cv::max(0, rect.x);int crop_y1 = cv::max(0, rect.y);int crop_x2 = cv::min(srcImage.cols, rect.x + rect.width); // 圖像范圍 0到cols-1, 0到rows-1 int crop_y2 = cv::min(srcImage.rows, rect.y + rect.height);int left_x = (-rect.x);int top_y = (-rect.y);int right_x = rect.x + rect.width - srcImage.cols;int down_y = rect.y + rect.height - srcImage.rows;//cv::Mat roiImage = srcImage(cv::Range(crop_y1, crop_y2 + 1), cv::Range(crop_x1, crop_x2 + 1)); cv::Mat roiImage = srcImage(cv::Rect(crop_x1, crop_y1, (crop_x2 - crop_x1), (crop_y2 - crop_y1)));if (top_y > 0 || down_y > 0 || left_x > 0 || right_x > 0)//只要存在邊界越界的情況,就需要邊界填充 {left_x = (left_x > 0 ? left_x : 0);right_x = (right_x > 0 ? right_x : 0);top_y = (top_y > 0 ? top_y : 0);down_y = (down_y > 0 ? down_y : 0);//cv::Scalar(0,0,255)指定顏色填充 cv::copyMakeBorder(roiImage, roiImage, top_y, down_y, left_x, right_x, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 255));//cv::copyMakeBorder(roiImage, roiImage, top_y, down_y, left_x, right_x, cv::BORDER_REPLICATE);//復制最邊緣像素 //cv::copyMakeBorder(roiImage, roiImage, top_y, down_y, left_x, right_x, BORDER_REFLECT_101); //邊緣對稱法填充 }//else//若不存在邊界越界的情況,則不需要填充了 //{ // destImage = roiImage; //} return roiImage;
}
int main(int argc)
{Mat src = imread("D:\\OpencvTest\\B1.jpg");//原始圖像是200*200 cv::imshow("src", src);cv::Rect rect(-50, -50, 300, 300);printf("src:[%d,%d]", src.cols, src.rows); printf("\n");cv::Mat crop_im1 = ImageCropPadding(src, rect);printf("rect:[%d,%d,%d,%d]", rect.x, rect.y, rect.width, rect.height);printf("\n");printf("crop_im1:[%d,%d]", crop_im1.cols, crop_im1.rows); printf("\n");cv::imshow("crop_im1", crop_im1);cvWaitKey(0);return 0;
}
這美女不錯吧,哈哈!注意,關注點不是美女,而是裁剪超出圖像的紅色區域。不過,對本人而言,我更喜歡復制邊緣像素的填充方法: 將原來copyMakeBorder函數參數改為:cv::BORDER_REPLICATEcv::copyMakeBorder(roiImage, destImage, top_y, down_y, left_x, right_x, cv::BORDER_REPLICATE);//復制邊緣像素填充
效果如下圖所示,是不是看到美女的手好細好長,美美噠~注意,關注點不是美女,而是裁剪超出圖像被復制的像素區域。
還有更妖媚的填充方法:
邊緣對稱法填充?,效果如下圖所示cv::copyMakeBorder(roiImage, destImage, top_y, down_y, left_x, right_x, BORDER_REFLECT_101); //邊緣對稱法填充
如果你覺得該帖子幫到你,還望貴人多多支持,鄙人會再接再厲,繼續努力的~
總結
以上是生活随笔為你收集整理的OpenCV图像剪切的扩展和高级用法:任意裁剪,边界扩充的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。