2015-02-17 14 views
8

Czy jest możliwe zmienianie rozmiaru obrazów o dowolnym kształcie lub rozmiarze, aby powiedzieć [500x500], ale zachowaj proporcje obrazu, aby puste miejsce wypełniło się białymi/czarnymi wypełniaczami ?Zmiana rozmiaru obrazu do kwadratu, ale zachowaj proporcje C++ opencv

więc powiedzieć, że obraz jest [2000x1000], po dostaniu się do [500x500] zmieniany co sam obraz rzeczywisty byłoby [500x250] z 125 obu stronach jest biały/czarny wypełniacz.

coś takiego:

Wejście

enter image description here

Wyjście

enter image description here

EDIT

Nie chcę po prostu wyświetlać obrazu w kwadratowym oknie, raczej zmienić obraz na ten stan, a następnie zapisać go w pliku, tworząc kolekcję obrazów o tym samym rozmiarze z możliwie najmniejszym zniekształceniem obrazu.

Jedyną rzeczą, z którą zetknąłem się z zadawaniem podobnego pytania, było this post, ale w php.

+3

Czy próbowałeś * czegokolwiek *? –

+0

Mogę zmienić rozmiar obrazów w porządku, jest to dodanie czerni, której nie znam. – MLMLTL

+1

Napełnij swoje tło czarnym, a następnie wklej obraz na nim ...? –

Odpowiedz

10

Nie w pełni zoptymalizowany, ale można spróbować to:

EDIT uchwyt wielkość docelową, która nie jest 500x500 pikseli i owijając go jako funkcja.

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; 
} 
+0

Zmieniłem kilka rzeczy, aby nowy obraz nie był rozciągnięty do rozmiaru 500 x 500 za każdym razem, ale do właściwie to, co kiedykolwiek ma rozmiar, ale poza tym, tak wspaniale! – MLMLTL

+0

Dzięki edycji, to po prostu doskonałe – MLMLTL

+1

świetnie, dzięki, btw, można również kontrolować kolor tła za pomocą parametru, ale zachowałem proste rzeczy .. –

1

Możesz utworzyć kolejny obraz o pożądanym formacie kwadratu, a następnie umieścić go na środku kwadratu. Coś takiego:

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#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; 
} 
5

Podejście ogólne:

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; 
} 
4

odpowiedź alireza jest dobra, jednak ja zmodyfikowany kod nieznacznie, tak że nie należy dodawać pionowych granic, gdy obraz pasuje pionowo i nie dodawaj poziomych krawędzi, gdy obraz pasuje w poziomie (jest to bliższe pierwotnej prośbie):

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; 
} 
+0

Twoje rozwiązanie jest niekompletne i nie jest oczywiste, jak należy zmodyfikować kod Alireza za pomocą Twój. – apk

+0

Zaktualizowano rozwiązanie, aby było bardziej kompletne –

Powiązane problemy