Cambiar el tamaño de una imagen a un cuadrado, pero mantener la relación de aspecto c ++ opencv

¿Hay una manera de cambiar el tamaño de las imágenes de cualquier forma o tamaño para decir [500x500] pero mantener la relación de aspecto de la imagen, al llenar el espacio vacío con relleno negro / blanco?

Entonces, digamos que la imagen es [2000x1000] , después de cambiar el tamaño a [500x500] la imagen real sería [500x250] , con 125 ambos lados como relleno blanco / negro.

Algo como esto:

Entrada

introduzca la descripción de la imagen aquí

Salida

introduzca la descripción de la imagen aquí

EDITAR

No deseo simplemente mostrar la imagen en una ventana cuadrada, sino cambiar la imagen a ese estado y luego guardarla en un archivo creando una colección de imágenes del mismo tamaño con la menor distorsión de imagen posible.

Lo único que encontré haciendo una pregunta similar fue esta publicación , pero está en php .

No está totalmente optimizado, pero puedes probar esto:

EDITE maneja el tamaño objective que no es 500x500 píxeles y lo envuelve como una función.

 cv::Mat GetSquareImage( const cv::Mat& img, int target_width = 500 ) { int width = img.cols, height = img.rows; cv::Mat square = cv::Mat::zeros( target_width, target_width, img.type() ); int max_dim = ( width >= height ) ? width : height; float scale = ( ( float ) target_width ) / max_dim; cv::Rect roi; if ( width >= height ) { roi.width = target_width; roi.x = 0; roi.height = height * scale; roi.y = ( target_width - roi.height ) / 2; } else { roi.y = 0; roi.height = target_width; roi.width = width * scale; roi.x = ( target_width - roi.width ) / 2; } cv::resize( img, square( roi ), roi.size() ); return square; } 

Un enfoque general:

 cv::Mat utilites::resizeKeepAspectRatio(const cv::Mat &input, const cv::Size &dstSize, const cv::Scalar &bgcolor) { cv::Mat output; double h1 = dstSize.width * (input.rows/(double)input.cols); double w2 = dstSize.height * (input.cols/(double)input.rows); if( h1 <= dstSize.height) { cv::resize( input, output, cv::Size(dstSize.width, h1)); } else { cv::resize( input, output, cv::Size(w2, dstSize.height)); } int top = (dstSize.height-output.rows) / 2; int down = (dstSize.height-output.rows+1) / 2; int left = (dstSize.width - output.cols) / 2; int right = (dstSize.width - output.cols+1) / 2; cv::copyMakeBorder(output, output, top, down, left, right, cv::BORDER_CONSTANT, bgcolor ); return output; } 

La respuesta de Alireza es buena, sin embargo, modifiqué el código ligeramente para no agregar los bordes verticales cuando la imagen se ajusta verticalmente y no agrego bordes horizontales cuando la imagen se ajusta horizontalmente (esto está más cerca de la solicitud original):

 cv::Mat utilites::resizeKeepAspectRatio(const cv::Mat &input, const cv::Size &dstSize, const cv::Scalar &bgcolor) { cv::Mat output; // initially no borders int top = 0; int down = 0; int left = 0; int right = 0; if( h1 <= dstSize.height) { // only vertical borders top = (dstSize.height - h1) / 2; down = top; cv::resize( input, output, cv::Size(dstSize.width, h1)); } else { // only horizontal borders left = (dstSize.width - w2) / 2; right = left; cv::resize( input, output, cv::Size(w2, dstSize.height)); } return output; } 

Puede crear otra imagen del tamaño cuadrado que desee, luego coloque la imagen en el centro de la imagen cuadrada. Algo como esto:

 #include  #include  #include "opencv2/imgproc/imgproc.hpp" int main(int argc, char *argv[]) { // read an image cv::Mat image1= cv::imread("/home/hdang/Desktop/colorCode.png"); //resize it cv::Size newSize = cv::Size(image1.cols/2,image1.rows/2); cv::resize(image1, image1, newSize, 0, 0, cv::INTER_LINEAR); //create the square container int dstWidth = 500; int dstHeight = 500; cv::Mat dst = cv::Mat(dstHeight, dstWidth, CV_8UC3, cv::Scalar(0,0,0)); //Put the image into the container, roi is the new position cv::Rect roi(cv::Rect(0,dst.rows*0.25,image1.cols,image1.rows)); cv::Mat targetROI = dst(roi); image1.copyTo(targetROI); //View the result cv::namedWindow("OpenCV Window"); cv::imshow("OpenCV Window", dst); // wait key for 5000 ms cv::waitKey(5000); return 0; }