c++ - pixeles - ejemplos opencv python
Girar cv:: Mat utilizando cv:: warpAffine compensa la imagen de destino (5)
He encontrado una solución que no involucra a warpAffine()
.
Pero antes de eso, debo declarar (para referencias futuras) que mi sospecha era correcta, que tenía que pasar el tamaño del destino al llamar a warpAffine()
:
warpAffine(image, rotated_img, rot_matrix, rotated_img.size());
Por lo que puedo decir, el borde negro (causado por la escritura en un desplazamiento) dibujado por esta función parece ser su comportamiento estándar. He notado esto con la interfaz C y también con la interfaz C ++ de OpenCV que se ejecuta en Mac y Linux, utilizando las versiones 2.3.1a y 2.3.0.
La solución que terminé usando es mucho más simple que toda esta cosa warp . Puede usar cv::transpose()
y cv::flip()
para rotar una imagen 90 grados. Aquí está:
Mat src = imread(argv[1], 1);
cv::Mat dst;
cv::transpose(src, dst);
cv::flip(dst, dst, 1);
imwrite("rotated90.jpg", dst);
---- I>
Estoy tratando de rotar una imagen de 1296x968 en 90 grados usando la API de C ++ de OpenCV y estoy enfrentando algunos problemas.
Entrada :
Rotado :
Como puede ver, la imagen girada tiene algunos problemas. Primero, tiene el mismo tamaño que el original, aunque creo específicamente el Mat
destino con el tamaño invertido del original. Como resultado, la imagen de destino se recorta.
Sospecho que esto está sucediendo porque estoy llamando a warpAffine()
y pasa el tamaño del Mat
original en lugar del tamaño del Mat
de destino. Pero estoy haciendo esto porque seguí esta respuesta , pero ahora sospecho que la respuesta puede estar equivocada. Así que esta es mi primera duda / problema.
El segundo, es que warpAffine()
está escribiendo en el destino en un cierto desplazamiento (probablemente para copiar los datos girados en el centro de la imagen) y esta operación deja un borde negro grande y horrible alrededor de la imagen.
¿Cómo soluciono estos problemas?
Estoy compartiendo el código fuente a continuación:
#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
void rotate(Mat& image, double angle)
{
Point2f src_center(image.cols/2.0F, image.rows/2.0F);
Mat rot_matrix = getRotationMatrix2D(src_center, angle, 1.0);
Mat rotated_img(Size(image.size().height, image.size().width), image.type());
warpAffine(image, rotated_img, rot_matrix, image.size());
imwrite("rotated.jpg", rotated_img);
}
int main(int argc, char* argv[])
{
Mat orig_image = imread(argv[1], 1);
if (orig_image.empty())
{
cout << "!!! Couldn''t load " << argv[1] << endl;
return -1;
}
rotate(orig_image, 90);
return 0;
}
Me doy cuenta de que ha encontrado otras soluciones más rápidas (la rotación de 90 grados debería ser muy rápida y no necesita toda la maquinaria de warpAffine), pero quiero abordar el problema del borde negro para cualquier persona que se encuentre con esto.
¿Qué más podría hacer warpAffine? Se especificó que la imagen de destino era más ancha que alta, y la transformación afín solo reflejaba la rotación (alrededor del centro de la imagen), no la escala. Eso es exactamente lo que hizo. No hay información en ningún lugar para decirle a warpAffine lo que debe dibujarse en esos bordes negros, por lo que los dejó negros.
Experimento físico directo: poner una hoja sobre la mesa. Dibuje un contorno a su alrededor (esto es lo que hizo cuando especificó que deseaba que el resultado tuviera la misma forma / tamaño que el original). Ahora gira esa hoja 90 grados alrededor de su centro. Mire la región limitada por el contorno en la tabla. Si fuera una mesa negra, se vería exactamente como tu resultado.
Mucha gente ha tenido problemas con la rotación de imágenes o fragmentos de imágenes debido a las compensaciones, etc. Por lo tanto, estoy publicando una solución para permitirle rotar una región (o toda) de una imagen y pegarla en otra imagen o tener la función calcular una imagen donde todo encajará.
// ROTATE p by R
/**
* Rotate p according to rotation matrix (from getRotationMatrix2D()) R
* @param R Rotation matrix from getRotationMatrix2D()
* @param p Point2f to rotate
* @return Returns rotated coordinates in a Point2f
*/
Point2f rotPoint(const Mat &R, const Point2f &p)
{
Point2f rp;
rp.x = (float)(R.at<double>(0,0)*p.x + R.at<double>(0,1)*p.y + R.at<double>(0,2));
rp.y = (float)(R.at<double>(1,0)*p.x + R.at<double>(1,1)*p.y + R.at<double>(1,2));
return rp;
}
//COMPUTE THE SIZE NEEDED TO LOSSLESSLY STORE A ROTATED IMAGE
/**
* Return the size needed to contain bounding box bb when rotated by R
* @param R Rotation matrix from getRotationMatrix2D()
* @param bb bounding box rectangle to be rotated by R
* @return Size of image(width,height) that will compleley contain bb when rotated by R
*/
Size rotatedImageBB(const Mat &R, const Rect &bb)
{
//Rotate the rectangle coordinates
vector<Point2f> rp;
rp.push_back(rotPoint(R,Point2f(bb.x,bb.y)));
rp.push_back(rotPoint(R,Point2f(bb.x + bb.width,bb.y)));
rp.push_back(rotPoint(R,Point2f(bb.x + bb.width,bb.y+bb.height)));
rp.push_back(rotPoint(R,Point2f(bb.x,bb.y+bb.height)));
//Find float bounding box r
float x = rp[0].x;
float y = rp[0].y;
float left = x, right = x, up = y, down = y;
for(int i = 1; i<4; ++i)
{
x = rp[i].x;
y = rp[i].y;
if(left > x) left = x;
if(right < x) right = x;
if(up > y) up = y;
if(down < y) down = y;
}
int w = (int)(right - left + 0.5);
int h = (int)(down - up + 0.5);
return Size(w,h);
}
/**
* Rotate region "fromroi" in image "fromI" a total of "angle" degrees and put it in "toI" if toI exists.
* If toI doesn''t exist, create it such that it will hold the entire rotated region. Return toI, rotated imge
* This will put the rotated fromroi piece of fromI into the toI image
*
* @param fromI Input image to be rotated
* @param toI Output image if provided, (else if &toI = 0, it will create a Mat fill it with the rotated image roi, and return it).
* @param fromroi roi region in fromI to be rotated.
* @param angle Angle in degrees to rotate
* @return Rotated image (you can ignore if you passed in toI
*/
Mat rotateImage(const Mat &fromI, Mat *toI, const Rect &fromroi, double angle)
{
//CHECK STUFF
// you should protect against bad parameters here ... omitted ...
//MAKE OR GET THE "toI" MATRIX
Point2f cx((float)fromroi.x + (float)fromroi.width/2.0,fromroi.y +
(float)fromroi.height/2.0);
Mat R = getRotationMatrix2D(cx,angle,1);
Mat rotI;
if(toI)
rotI = *toI;
else
{
Size rs = rotatedImageBB(R, fromroi);
rotI.create(rs,fromI.type());
}
//ADJUST FOR SHIFTS
double wdiff = (double)((cx.x - rotI.cols/2.0));
double hdiff = (double)((cx.y - rotI.rows/2.0));
R.at<double>(0,2) -= wdiff; //Adjust the rotation point to the middle of the dst image
R.at<double>(1,2) -= hdiff;
//ROTATE
warpAffine(fromI, rotI, R, rotI.size(), INTER_CUBIC, BORDER_CONSTANT, Scalar::all(0));
//& OUT
return(rotI);
}
Tal vez esto pueda ayudar a alguien.
las variables son
img: imagen original
ángulo: grados
escala
dst: imagen de destino
int width = img.size().width,
height = img.size().height;
Mat rot = getRotationMatrix2D(Point2f(0,0), angle, scale)/scale; //scale later
double sinv = rot.at<double>(0,1),
cosv = rot.at<double>(0,0);
rot.at<double>(1,2) = width*sinv; //adjust row offset
Size dstSize(width*cosv + height*sinv, width*sinv + height*cosv);
Mat dst;
warpAffine(img, dst, rot, dstSize);
resize(dst, dst, Size(), scale, scale); //scale now
Un problema que encontré es que el tamaño de la imagen de destino para warpAffine
se establece en image.size()
lugar de rotated_img.size()
. Sin embargo, después de la urdimbre, aún se traduce demasiado lejos en x e y ... Intenté exactamente la misma urdimbre
[ 6.123031769111886e-17 1 163.9999999999999;
-1 6.123031769111886e-17 1132;
0 0 1]
de getRotationMatrix2D de OpenCV en Matlab, y funcionó perfectamente. Estoy empezando a oler un posible error con warpAffine
...