关闭

[置顶] OpenCV图像剪切的扩展和高级用法:任意裁剪,边界扩充

标签: 指定填充背景颜色边界颜色copyMakeBorder的用法OpenCV图像边界边缘填充OpenCV图像剪切
8156人阅读 评论(11) 收藏 举报
分类:

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_REPLICATE
cv::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); //边缘对称法填充 
如果你觉得该帖子帮到你,还望贵人多多支持,鄙人会再接再厉,继续努力的~
7
3
查看评论

openCv--裁剪图像不规则区域

得到图像中感兴趣的不规则的区域分为三步,分别如下: 1.在原图上用cvLine画出自己感兴趣的区域,比如这个区域可以有几个线段围起来,就用cvLine将所有的线段连起来 cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, i...
  • yuan13091324
  • yuan13091324
  • 2015-07-28 16:41
  • 3960

opencv surf 匹配之后的RANSAC降噪

RANSAC算法查看Multiple View Geometry in Computer Vision
  • superyuanzhe
  • superyuanzhe
  • 2014-04-21 20:32
  • 3129

opencv surf 实现细节

Surf算法是一把牛刀,我们可以很轻易的从网上或各种OpenCV教程里找到Surf的用例,把例程中的代码或贴或敲过来,满心期待的按下F5,当屏幕终于被满屏花花绿绿的小圆点或者N多道连接线条霸占时,内心的民族自豪感油然而生,仿佛屠龙宝刀在手,屁颠屁颠的很开心。 如果对Surf的探究或...
  • B10090411
  • B10090411
  • 2016-11-30 11:43
  • 1605

Opencv 图像分割: 阈值化分割 区域分割 边缘分割

Opencv 图像分割: 阈值化分割 区域分割 边缘分割 卷积 就是两个函数之间的相互关系,然后得出一个新的值,在连续空间做积分计算,然后在离散空间内求和的过程。 在计算机视觉里面,可以把卷积当做一个抽象的过程,就是把小区域内的信息统计抽象出来 图像阈值化分割 按照灰度级,对像素集合...
  • keen_zuxwang
  • keen_zuxwang
  • 2017-05-26 11:36
  • 1559

OPENCV图像边缘查找与分割技术在android中使用汇总

图像分割技术或者叫抠图技术,是一种根据需要对图像进行截取分离的技术,在一般的图像处理和视频处理中应用十分广泛,是图像查找,图像识别,图像特效的基础。经常被人们使用在相机美颜,自动人脸马赛克,车牌识别,图像查找,人脸查找,人脸识别,机器视觉,AR等领域。图像分割分有标注和无标注两种情况,一种是自动根据...
  • blogercn
  • blogercn
  • 2017-09-12 02:33
  • 920

opencv3_java 图像的修剪裁剪Trimming Rect

图像的修剪裁剪Trimming Rect package opencv_java_demo; import org.opencv.core.*; import org.opencv.imgcodecs.*; import org.opencv.imgproc.Imgproc; public ...
  • sileixinhua
  • sileixinhua
  • 2017-05-31 21:00
  • 943

快速对图像的像素进行操作 opencv 实战

OpenCV 如何对图像的像素进行操作 2013年10月03日 ⁄ 综合⁄ 共 2952字 ⁄ 字号 小 中 大 ⁄ 评论关闭 对图像的像素进行操作,我们可以实现空间增强,反色等目的。让我们先来看一下内存空间中图像矩阵,也就是Mat的矩阵数值部分是怎么存储的: 如果图像是一幅灰度图像,他就像这...
  • zwlq1314521
  • zwlq1314521
  • 2015-04-14 10:17
  • 33907

opencv学习(三十一)之图像边缘像素填充估计copyMakeBorder()

前面讲到图像卷积运算的时候涉及到对图像边缘像素的估计,这里讲介绍图像边缘像素进行卷积运算。大部分opencv中的函数是将原图像复制到一个比原图像尺寸更大的图像中然后实现边缘的自动填充。这种方式得到的像素点可以执行卷积操作。下面介绍两种方式: - 1.BORDER_CONSTANT:使用一个常数填充...
  • keith_bb
  • keith_bb
  • 2017-02-15 17:55
  • 580

OpenCV截取图像的任意形状区域,规则的图形(圆、椭圆、矩形),不规则鼠标自己选择

OpenCV截取图像的任意形状区域(ROI),规则的图形(圆、椭圆、矩形),不规则鼠标自己选择
  • zang141588761
  • zang141588761
  • 2015-12-17 09:13
  • 5984

opencv切割并保存图片

使用opencv切割并保存图片,需要使用Rect类进行操作。 这里讨论如何加载图片,切割图片,保存图片,销毁窗口和waitKey()函数的用法。 #include #include using namespace std; using namespace cv; int main(){ ...
  • LordofRobots
  • LordofRobots
  • 2017-05-16 17:21
  • 2299
    个人资料
    • 访问:552558次
    • 积分:5880
    • 等级:
    • 排名:第5195名
    • 原创:106篇
    • 转载:51篇
    • 译文:1篇
    • 评论:174条
    博客专栏
    最新评论