OpenCV基础(4)使用OpenCV裁剪图像

首先,为什么我们需要作物?裁剪是为了从图像中移除所有不需要的物体或区域或者是突出图像的一个特殊特征。

与Numpy使用切片操作实现裁剪不同,OpenCV没有特定的函数来进行裁剪操作。读取的每个图像都存储在一个2D数组中(对于每个颜色通道)。只需指定要裁剪的区域的高度和宽度(以像素为单位)即可。

1.简单版本代码实现

下面的代码片段展示了如何使用Python和c++裁剪图像。在后面的文章中,你将会更详细地了解这些。
(1)Python

# 导入相关包
import cv2
import numpy as np

img = cv2.imread('test.jpg')
print(img.shape) # Print image shape
cv2.imshow("original", img)

# 裁剪图像
cropped_image = img[80:280, 150:330]

# 显示裁剪图像
cv2.imshow("cropped", cropped_image)

# 保存裁剪图像
cv2.imwrite("Cropped Image.jpg", cropped_image)

cv2.waitKey(0)
cv2.destroyAllWindows()

(2)C++

// 包含库文件
#include
#include

// 命名空间
using namespace std;
using namespace cv;

int main()
{
	// 读取图像
	Mat img = imread("test.jpg");
	cout << "Width : " << img.size().width << endl;
	cout << "Height: " << img.size().height << endl;
	cout<<"Channels: :"<< img.channels() << endl;
	// 裁剪图像
	Mat cropped_image = img(Range(80,280), Range(150,330));

	//显示裁剪图像
	imshow(" Original Image", img);
	imshow("Cropped Image", cropped_image);

	//保存裁剪图像
	imwrite("Cropped Image.jpg", cropped_image);

	// 等待任意键输入才退出
	waitKey(0);
	destroyAllWindows();
	return 0;
}

2.代码解析

在Python中,使用与NumPy数组切片相同的方法裁剪图像。要对数组进行切片,需要指定第一个维度和第二个维度的开始和结束索引。

  • 第一个维度是图像的行数或高度。
  • 第二个维度是图像的列数或宽度。

按照惯例,2D数组的第一维表示数组的行(其中每一行表示图像的y坐标)。如何切片一个NumPy数组?看看这个例子中的语法:cropped = img[start_row:end_row, start_col:end_col]

在c++中,我们使用Range()函数来裁剪图像。

  • 与Python一样,它也应用了切片。
  • 在这里,图像也是作为2D矩阵读入的,遵循上面描述的约定。

下面是裁剪图像的c++语法:img(Range(start_row, end_row), Range(start_col, end_col))

3. 使用裁剪将图像分割成小块

OpenCV中裁剪的一个实际应用是将图像分割成更小的块。使用循环从图像中裁剪出一个片段。
(1) Python

# 导入相关包
import cv2
import numpy as np
img =  cv2.imread("test.png")
image_copy = img.copy() 
imgheight=img.shape[0]
imgwidth=img.shape[1]

M = 83
N = 124
x1 = 0
y1 = 0

for y in range(0, imgheight, M):
    for x in range(0, imgwidth, N):
        if (imgheight - y) < M or (imgwidth - x) < N:
            break
            
        y1 = y + M
        x1 = x + N

        # 检查块的坐标是否超过图像的宽度或高度
        if x1 >= imgwidth and y1 >= imgheight:
            x1 = imgwidth - 1
            y1 = imgheight - 1
            #切成大小为MxN的小块
            tiles = image_copy[y:y1, x:x1]
            #将每个块保存到文件目录中
            cv2.imwrite('saved_patches/'+'tile'+str(x)+'_'+str(y)+'.jpg', tiles)
            cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
        elif y1 >= imgheight: # 当块高度超过图像高度时
            y1 = imgheight - 1
            #裁切成大小为MxN的块
            tiles = image_copy[y:y+M, x:x+N]
            #将每个块保存到文件目录中
            cv2.imwrite('saved_patches/'+'tile'+str(x)+'_'+str(y)+'.jpg', tiles)
            cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
        elif x1 >= imgwidth: # 当块宽度超过图像宽度时
            x1 = imgwidth - 1
            #裁切成大小为MxN的块
            tiles = image_copy[y:y+M, x:x+N]
            #将每个块保存到文件目录中
            cv2.imwrite('saved_patches/'+'tile'+str(x)+'_'+str(y)+'.jpg', tiles)
            cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
        else:
            #裁切成大小为MxN的块
            tiles = image_copy[y:y+M, x:x+N]
            #将每个块保存到文件目录中
            cv2.imwrite('saved_patches/'+'tile'+str(x)+'_'+str(y)+'.jpg', tiles)
            cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
#将整张图象保存到文件目录中
cv2.imshow("Patched Image",img)
cv2.imwrite("patched.jpg",img)
 
cv2.waitKey()
cv2.destroyAllWindows()

(2)C++

// 包含库文件
#include
#include

// 命名空间
using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("test.png");
	Mat image_copy = img.clone();
	int imgheight = img.rows;
	int imgwidth = img.cols;
	int M = 83;
	int N = 124;
	
	int x1 = 0;
	int y1 = 0;
	for (int y = 0; y<imgheight; y=y+M)
	{
	    for (int x = 0; x<imgwidth; x=x+N)
	    {
	        if ((imgheight - y) < M || (imgwidth - x) < N)
	        {
	            break;
	        }
	        y1 = y + M;
	        x1 = x + N;
	        string a = to_string(x);
	        string b = to_string(y);
	
	        if (x1 >= imgwidth && y1 >= imgheight)
	        {
	            x = imgwidth - 1;
	            y = imgheight - 1;
	            x1 = imgwidth - 1;
	            y1 = imgheight - 1;
	
	            // 裁切成大小为MxN的块
	            Mat tiles = image_copy(Range(y, imgheight), Range(x, imgwidth));
	            //将每个块保存到文件目录中
	            imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);  
	            rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);    
	        }
	        else if (y1 >= imgheight)
	        {
	            y = imgheight - 1;
	            y1 = imgheight - 1;
	
	            // 裁切成大小为MxN的块
	            Mat tiles = image_copy(Range(y, imgheight), Range(x, x+N));
	            //将每个块保存到文件目录中
	            imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);  
	            rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);    
	        }
	        else if (x1 >= imgwidth)
	        {
	            x = imgwidth - 1;   
	            x1 = imgwidth - 1;
	
	            // 裁切成大小为MxN的块
	            Mat tiles = image_copy(Range(y, y+M), Range(x, imgwidth));
	            //将每个块保存到文件目录中
	            imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);  
	            rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);    
	        }
	        else
	        {
	            // 裁切成大小为MxN的块
	            Mat tiles = image_copy(Range(y, y+M), Range(x, x+N));
	            //将每个块保存到文件目录中
	            imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);  
	            rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);    
	        }
	    }
	}
	imshow("Patched Image", img);
	imwrite("patched.jpg",img);
	waitKey();
	destroyAllWindows();
	return 0;
}

OpenCV基础(4)使用OpenCV裁剪图像_第1张图片

4.使用裁剪的一些有趣应用

  • 可以使用裁剪从图像中提取感兴趣的区域,并丢弃不需要使用的其他部分。
  • 你可以从图像中提取小块来训练基于小块的神经网络。

总结

在这篇博客中,我们讨论了用c++和Python裁剪图像的基本语法。裁剪操作是通过切片来进行的,即我们指定要裁剪的高度和宽度或区域作为图像矩阵的维数。因此,生成的图像可以保存在一个新的矩阵中,或者通过更新现有的矩阵来保存。然后可以使用OpenCV imshow()函数将这个矩阵显示为图像,或者使用OpenCV imwrite()函数将其作为文件写入磁盘。我们还讨论了如何将图像分割成更小的块,以及围绕它的一些应用程序。

参考目录

https://learnopencv.com/cropping-an-image-using-opencv/

你可能感兴趣的:(OpenCV,opencv,python,C++)