Je dois faire pivoter une image de 90, 180 ou 270 degrés. Dans OpenCV4Android, je peux utiliser:
Imgproc.getRotationMatrix2D(new Point(center, center), degrees, 1);
Imgproc.warpAffine(src, dst, rotationMatrix, dst.size());
Cependant, ceci est un énorme goulot d'étranglement dans mon algorithme de traitement d'image. Bien entendu, une simple rotation par un multiple de 90 degrés est beaucoup plus simple que le cas le plus général de warpAffine
et peut être effectuée beaucoup plus efficacement. Pour 180 degrés, par exemple, je pourrais utiliser:
Core.flip(src, dst, -1);
où -1 signifie basculer entre les axes horizontal et vertical. Existe-t-il une optimisation similaire que je pourrais utiliser pour des rotations de 90 ou 270 degrés?
Il s’agit du premier résultat obtenu avec Google et aucune de ces solutions ne répond réellement à la question, ni n’est correcte ni succincte.
Core.rotate(Mat src, Mat dst, Core.ROTATE_90_CLOCKWISE); //ROTATE_180 or ROTATE_90_COUNTERCLOCKWISE
Je ne connais pas très bien l’API Java, ces codes sont développés par c ++ . Les logiques doivent être identiques, utilisez transpose + flip pour faire pivoter l’image avec 90n (n appartient à N = -valeur minimale de int, ....., -3, -2, -1, 0, 1, 2, 3, ..., valeur maximale de int)
/*
*@brief rotate image by multiple of 90 degrees
*
*@param source : input image
*@param dst : output image
*@param angle : factor of 90, even it is not factor of 90, the angle
* will be mapped to the range of [-360, 360].
* {angle = 90n; n = {-4, -3, -2, -1, 0, 1, 2, 3, 4} }
* if angle bigger than 360 or smaller than -360, the angle will
* be map to -360 ~ 360.
* mapping rule is : angle = ((angle / 90) % 4) * 90;
*
* ex : 89 will map to 0, 98 to 90, 179 to 90, 270 to 3, 360 to 0.
*
*/
void rotate_image_90n(cv::Mat &src, cv::Mat &dst, int angle)
{
if(src.data != dst.data){
src.copyTo(dst);
}
angle = ((angle / 90) % 4) * 90;
//0 : flip vertical; 1 flip horizontal
bool const flip_horizontal_or_vertical = angle > 0 ? 1 : 0;
int const number = std::abs(angle / 90);
for(int i = 0; i != number; ++i){
cv::transpose(dst, dst);
cv::flip(dst, dst, flip_horizontal_or_vertical);
}
}
Edit: Améliorer les performances, merci pour les commentaires de TimZaman et la mise en œuvre de 1 ''
void rotate_90n(cv::Mat const &src, cv::Mat &dst, int angle)
{
CV_Assert(angle % 90 == 0 && angle <= 360 && angle >= -360);
if(angle == 270 || angle == -90){
// Rotate clockwise 270 degrees
cv::transpose(src, dst);
cv::flip(dst, dst, 0);
}else if(angle == 180 || angle == -180){
// Rotate clockwise 180 degrees
cv::flip(src, dst, -1);
}else if(angle == 90 || angle == -270){
// Rotate clockwise 90 degrees
cv::transpose(src, dst);
cv::flip(dst, dst, 1);
}else if(angle == 360 || angle == 0 || angle == -360){
if(src.data != dst.data){
src.copyTo(dst);
}
}
}
Cela fera pivoter une image d’un nombre quelconque de degrés, en utilisant le moyen le plus efficace pour des multiples de 90.
void
rotate_cw(const cv::Mat& image, cv::Mat& dest, int degrees)
{
switch (degrees % 360) {
case 0:
dest = image.clone();
break;
case 90:
cv::flip(image.t(), dest, 1);
break;
case 180:
cv::flip(image, dest, -1);
break;
case 270:
cv::flip(image.t(), dest, 0);
break;
default:
cv::Mat r = cv::getRotationMatrix2D({image.cols/2.0F, image.rows/2.0F}, degrees, 1.0);
int len = std::max(image.cols, image.rows);
cv::warpAffine(image, dest, r, cv::Size(len, len));
break; //image size will change
}
}
Mais avec opencv 3.0, cela se fait simplement via la commande cv :: rotate :
cv::rotate(image, dest, e.g. cv::ROTATE_90_COUNTERCLOCKWISE);
Voici une solution utilisant l'API Android. Ici, je l’utilise pour faire pivoter les images d’une caméra pouvant être montées dans différentes orientations.
if (mCameraOrientation == 270) {
// Rotate clockwise 270 degrees
Core.flip(src.t(), dst, 0);
} else if (mCameraOrientation == 180) {
// Rotate clockwise 180 degrees
Core.flip(src, dst, -1);
} else if (mCameraOrientation == 90) {
// Rotate clockwise 90 degrees
Core.flip(src.t(), dst, 1);
} else if (mCameraOrientation == 0) {
// No rotation
dst = src;
}
Voici ma traduction en Python (et merci à toutes les affiches):
import cv2
def rot90(img, rotflag):
""" rotFlag 1=CW, 2=CCW, 3=180"""
if rotflag == 1:
img = cv2.transpose(img)
img = cv2.flip(img, 1) # transpose+flip(1)=CW
Elif rotflag == 2:
img = cv2.transpose(img)
img = cv2.flip(img, 0) # transpose+flip(0)=CCW
Elif rotflag ==3:
img = cv2.flip(img, -1) # transpose+flip(-1)=180
Elif rotflag != 0: # if not 0,1,2,3
raise Exception("Unknown rotation flag({})".format(rotflag))
return img
J'ai écrit cette version Python en utilisant uniquement Numpy
, qui sont beaucoup plus rapides qu'en utilisant cv2.transpose()
et cv2.flip()
.
def rotate_image_90(im, angle):
if angle % 90 == 0:
angle = angle % 360
if angle == 0:
return im
Elif angle == 90:
return im.transpose((1,0, 2))[:,::-1,:]
Elif angle == 180:
return im[::-1,::-1,:]
Elif angle == 270:
return im.transpose((1,0, 2))[::-1,:,:]
else:
raise Exception('Error')
Vous pouvez faire pivoter l'image à l'aide de la fonction numpy rot90
comme
def rotate_image(image,deg):
if deg ==90:
return np.rot90(image)
if deg ==180:
return np.rot90(image,2)
if deg == 270:
return np.rot90(image,-1) #Reverse 90 deg rotation
J'espère que cette aide ..
Utilisez le numpy.rot90
, si vous voulez 180 degrés, faites-le deux fois.
import numpy as np
import cv2
img = cv2.imread('img.png',1)
cv2.imshow('',img)
cv2.waitKey(0)
img90 = np.rot90(img)
cv2.imshow('',img90)
cv2.waitKey(0)
En python:
# import the necessary packages
import numpy as np
import cv2
# initialize the camera and grab a reference to the raw camera capture
vs = cv2.VideoCapture(0)
(ret, image_original) = vs.read()
image_rotated_90 = np.rot90(image_original)
image_rotated_180 = np.rot90(image_rotated_90)
# show the frame and press any key to quit the image frame
cv2.imshow("Frame", image_rotated_180)
cv2.waitKey(0)