トリミングとは、画像から不要なオブジェクトや領域を削除することです。画像の特定の特徴を強調表示することもできます。
OpenCV にはトリミングのための特定の関数はなく、NumPy 配列のスライスがその役割を果たします。読み取られた各画像は 2D 配列に (カラー チャネルごとに) 保存されます。切り抜きたい領域の高さと幅をピクセル単位で指定するだけで完了です。
OpenCVを使用した画像のトリミング
1. OpenCVによるトリミング
次のコード スニペットは、Python と C++ を使用して画像をトリミングする方法を示しています。これらについては、例の後半で詳しく説明します。
パイソン
# Import packages
import cv2
import numpy as np
img = cv2.imread('test.jpg')
print(img.shape) # Print image shape
cv2.imshow("original", img)
# Cropping an image
cropped_image = img[400:1200, 350:700]
# Display cropped image
cv2.imshow("cropped", cropped_image)
# Save the cropped image
cv2.imwrite("Cropped Image.jpg", cropped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++
// Include Libraries
#include<opencv2/opencv.hpp>
#include<iostream>
// Namespace nullifies the use of cv::function();
using namespace std;
using namespace cv;
int main()
{
// Read image
Mat img = imread("test.jpg");
cout << "Width : " << img.size().width << endl;
cout << "Height: " << img.size().height << endl;
cout<<"Channels: :"<< img.channels() << endl;
// Crop image
Mat cropped_image = img(Range(400,1200), Range(350,700));
//display image
imshow(" Original Image", img);
imshow("Cropped Image", cropped_image);
//Save the cropped Image
imwrite("Cropped Image.jpg", cropped_image);
// 0 means loop infinitely
waitKey(0);
destroyAllWindows();
return 0;
}
上記のコードは、画像とその寸法を読み取って表示します。寸法には、2D マトリックスの幅と高さだけでなく、チャネル数も含まれます (たとえば、RGB 画像には赤、緑、青の 3 つのチャネルがあります)。
画像の美しい女性が写っている部分を切り取ってみましょう。
パイソン
cropped_image = img[400:1200, 350:700] # Slicing to crop the image
# Display the cropped image
cv2.imshow("cropped", cropped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++
Mat crop = img(Range(400,1200),Range(350,700)); // Slicing to crop the image
// Display the cropped image
imshow("Cropped Image", crop);
waitKey(0);
destroyAllWindows();
return 0;
Python では、NumPy 配列のスライスと同じ方法で画像をトリミングできます。配列をスライスするには、1 番目と 2 番目の次元の開始インデックスと終了インデックスを指定する必要があります。
- 最初の次元は常に行数または画像の高さです。
- 2 番目の次元は、画像の列数または幅です。
画像の 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))
2. クロップ機能を使って画像を分割する
OpenCV でのトリミングの実際の応用例は、画像を同じサイズの画像パッチに分割することです。ループを使用して画像からセグメントを切り抜きます。まず、画像の形状から目的の画像ブロックの高さと幅を取得します。
パイソン
img = cv2.imread("test_cropped.jpg")
image_copy = img.copy()
imgheight=img.shape[0]
imgwidth=img.shape[1]
C++
Mat img = imread("test_cropped.jpg");
Mat image_copy = img.clone();
int imgheight = img.rows;
int imgwidth = img.cols;
高さと幅をロードして、小さい画像タイルをトリミングする必要がある範囲を指定します。これには、Python の range() 関数を使用します。次に、2 つのループを使用して切り抜きます。
- 幅の範囲
- 身長の範囲
元の画像ブロックの高さと幅は (1350, 1080) であり、使用する画像ブロックの高さと幅はそれぞれ (270, 216) であることが知られています。内側と外側のループのストライド (画像内で移動するピクセル数) は、25 の画像ブロックに分割されます。(パズルのように)
パイソン
M = 216
N = 270
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
# check whether the patch width or height exceeds the image width or height
if x1 >= imgwidth and y1 >= imgheight:
x1 = imgwidth - 1
y1 = imgheight - 1
# Crop into patches of size MxN
tiles = image_copy[y:y + M, x:x + N]
# Save each patch into file directory
cv2.imwrite(str(x) + '_' + str(y) + '.jpg', tiles)
cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
elif y1 >= imgheight: # when patch height exceeds the image height
y1 = imgheight - 1
# Crop into patches of size MxN
tiles = image_copy[y:y + M, x:x + N]
# Save each patch into file directory
cv2.imwrite(str(x) + '_' + str(y) + '.jpg', tiles)
cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
elif x1 >= imgwidth: # when patch width exceeds the image width
x1 = imgwidth - 1
# Crop into patches of size MxN
tiles = image_copy[y:y + M, x:x + N]
# Save each patch into file directory
cv2.imwrite(str(x) + '_' + str(y) + '.jpg', tiles)
cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
else:
# Crop into patches of size MxN
tiles = image_copy[y:y + M, x:x + N]
# Save each patch into file directory
cv2.imwrite(str(x) + '_' + str(y) + '.jpg', tiles)
cv2.rectangle(img, (x, y), (x1, y1), (0, 255, 0), 1)
C++
int M = 216;
int N = 270;
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;
// crop the patches of size MxN
Mat tiles = image_copy(Range(y, imgheight), Range(x, imgwidth));
//save each patches into file directory
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;
// crop the patches of size MxN
Mat tiles = image_copy(Range(y, imgheight), Range(x, x+N));
//save each patches into file directory
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;
// crop the patches of size MxN
Mat tiles = image_copy(Range(y, y+M), Range(x, imgwidth));
//save each patches into file directory
imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);
rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);
}
else
{
// crop the patches of size MxN
Mat tiles = image_copy(Range(y, y+M), Range(x, x+N));
//save each patches into file directory
imwrite("saved_patches/tile" + a + '_' + b + ".jpg", tiles);
rectangle(img, Point(x,y), Point(x1,y1), Scalar(0,255,0), 1);
}
}
}
次に、imshow() 関数を使用して画像タイル モザイクを表示します。imwrite() 関数を使用してファイル ディレクトリに保存します。
パイソン
#Save full image into file directory
cv2.imshow("Patched Image",img)
cv2.imwrite("patched.jpg",img)
cv2.waitKey()
cv2.destroyAllWindows()
C++
imshow("Patched Image", img);
imwrite("patched.jpg",img);
waitKey();
destroyAllWindows();
パイソン
C++