opencv - rotar - Girar la imagen 90, 180 o 270 grados
rotar imagen opencv (9)
Necesito rotar una imagen 90, 180 o 270 grados. En OpenCV4Android puedo usar:
Imgproc.getRotationMatrix2D(new Point(center, center), degrees, 1);
Imgproc.warpAffine(src, dst, rotationMatrix, dst.size());
Sin embargo, este es un gran cuello de botella en mi algoritmo de procesamiento de imágenes. Por supuesto, una simple rotación por un múltiplo de 90 grados es mucho más simple que el caso más general de warpAffine
, y se puede hacer de manera mucho más eficiente. Para 180 grados, por ejemplo, podría usar:
Core.flip(src, dst, -1);
donde -1 significa dar la vuelta a los ejes horizontal y vertical. ¿Existe una optimización similar que pueda usar para rotaciones de 90 o 270 grados?
Aquí está mi traducción de Python (y gracias a todos los carteles):
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
Aquí hay una solución que usa la API de Android. Aquí, lo estoy usando para rotar imágenes de una cámara que podría montarse en varias orientaciones.
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;
}
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)
Escribí esta versión de Python usando solo Numpy
, que es mucho más rápido que usar cv2.transpose()
y 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'')
Este es el primer resultado cuando Google y ninguna de estas soluciones realmente responde la pregunta o es correcta o sucinta.
Core.rotate(Mat src, Mat dst, Core.ROTATE_90_CLOCKWISE); //ROTATE_180 or ROTATE_90_COUNTERCLOCKWISE
Esto rotará una imagen en cualquier número de grados, utilizando los medios más eficientes para múltiplos 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
}
}
Pero con opencv 3.0, esto se hace solo a través del comando cv::rotate :
cv::rotate(image, dest, e.g. cv::ROTATE_90_COUNTERCLOCKWISE);
No sé muy bien la API de Java, estos códigos están desarrollados por c ++. Las lógicas deben ser las mismas, use transpose + flip para rotar la imagen con 90n (n pertenece a N = valor mínimo de int, ....., -3, -2, -1, 0, 1, 2, 3, ..., valor máximo 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);
}
}
Editar: mejorar el rendimiento, gracias por los comentarios de TimZaman y la implementación 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);
}
}
}
Puede rotar la imagen usando la función numpy rot90
me gusta
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
Espero que esto ayude ..
Usa numpy.rot90
, si quieres 180 grados, solo hazlo dos veces.
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)