次の写真は、私が欲しいものを教えてくれます。
画像内の長方形の情報(幅、高さ、中心点、回転度)があります。今、それらを切り取って画像として保存するスクリプトを書きたいと思いますが、まっすぐにすることもできます。のように、画像の内側に表示されている長方形から外側に表示されている長方形に移動したいと考えています。
OpenCV Python を使用しています。これを実現する方法を教えてください。
OpenCV Python の例は見つけにくいので、いくつかのコードを示してください。
次の写真は、私が欲しいものを教えてくれます。
画像内の長方形の情報(幅、高さ、中心点、回転度)があります。今、それらを切り取って画像として保存するスクリプトを書きたいと思いますが、まっすぐにすることもできます。のように、画像の内側に表示されている長方形から外側に表示されている長方形に移動したいと考えています。
OpenCV Python を使用しています。これを実現する方法を教えてください。
OpenCV Python の例は見つけにくいので、いくつかのコードを示してください。
この関数を使用してwarpAffine
、定義された中心点を中心に画像を回転できます。getRotationMatrix2D
適切な回転行列は(ここtheta
で、 は度数)を使用して生成できます。
その後、Numpy slicingを使用して画像を切り取ることができます。
import cv2
import numpy as np
def subimage(image, center, theta, width, height):
'''
Rotates OpenCV image around center with angle theta (in deg)
then crops the image according to width and height.
'''
# Uncomment for theta in radians
#theta *= 180/np.pi
shape = ( image.shape[1], image.shape[0] ) # cv2.warpAffine expects shape in (length, height)
matrix = cv2.getRotationMatrix2D( center=center, angle=theta, scale=1 )
image = cv2.warpAffine( src=image, M=matrix, dsize=shape )
x = int( center[0] - width/2 )
y = int( center[1] - height/2 )
image = image[ y:y+height, x:x+width ]
return image
出力画像dsize
の形状であることに注意してください。パッチ/角度が十分に大きい場合、単純化のために上記のように元の形状を使用すると、エッジが切り取られます (上の画像を比較)。この場合、(出力イメージを拡大するため) にスケーリング係数を導入し、スライスの基準点 (ここでは) を導入できます。shape
center
上記の関数は次のように使用できます。
image = cv2.imread('owl.jpg')
image = subimage(image, center=(110, 125), theta=30, width=100, height=200)
cv2.imwrite('patch.jpg', image)
これは、同じタスクを実行する私の C++ バージョンです。少し遅いことに気付きました。この機能のパフォーマンスを向上させる何かを誰かが見つけたら、私に知らせてください。:)
bool extractPatchFromOpenCVImage( cv::Mat& src, cv::Mat& dest, int x, int y, double angle, int width, int height) {
// obtain the bounding box of the desired patch
cv::RotatedRect patchROI(cv::Point2f(x,y), cv::Size2i(width,height), angle);
cv::Rect boundingRect = patchROI.boundingRect();
// check if the bounding box fits inside the image
if ( boundingRect.x >= 0 && boundingRect.y >= 0 &&
(boundingRect.x+boundingRect.width) < src.cols &&
(boundingRect.y+boundingRect.height) < src.rows ) {
// crop out the bounding rectangle from the source image
cv::Mat preCropImg = src(boundingRect);
// the rotational center relative tot he pre-cropped image
int cropMidX, cropMidY;
cropMidX = boundingRect.width/2;
cropMidY = boundingRect.height/2;
// obtain the affine transform that maps the patch ROI in the image to the
// dest patch image. The dest image will be an upright version.
cv::Mat map_mat = cv::getRotationMatrix2D(cv::Point2f(cropMidX, cropMidY), angle, 1.0f);
map_mat.at<double>(0,2) += static_cast<double>(width/2 - cropMidX);
map_mat.at<double>(1,2) += static_cast<double>(height/2 - cropMidY);
// rotate the pre-cropped image. The destination image will be
// allocated by warpAffine()
cv::warpAffine(preCropImg, dest, map_mat, cv::Size2i(width,height));
return true;
} // if
else {
return false;
} // else
} // extractPatch