Ask Your Question
0

Displaying multiple images

asked 2016-01-08 04:35:09 -0600

updated 2016-01-08 15:54:31 -0600

Hi All,

i tried to update an outdated sample code on opencv/wiki

The changes I have made up to now are as follows.

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace std;

int showManyImages( const String winName, const vector<Mat> images );

int main( int argc, char** argv )
{
    vector<Mat> images;

    for ( int i = 0; i < 15; i++ )
    {
        Mat image( 240,320,CV_8UC3, Scalar( (rand()&255), (rand()&255), (rand()&255) ));
        circle( image, Point( image.cols / 2, image.rows / 2 ), image.cols / 3, Scalar( (rand()&255), (rand()&255), (rand()&255) ) );
        images.push_back( image );
        showManyImages("showManyImages test", images);
        waitKey();
    }
    return 0;
}

int showManyImages( const String winName, const vector<Mat> images )
{
    int nImg = images.size() > 12 ? 12 : (int)images.size();

    int size;
    int x, y;

    // w - Maximum number of images in a row
    // h - Maximum number of images in a column
    int w, h;
    // scale - How much we have to resize the image
    float scale;
    int max;

    // TODO: code-block #1 - should be replaced with more robust code 
    // start of code-block #1
    if (nImg <= 0) 
    {
        return -1;
    }
    else if (nImg == 1)
    {
        w = h = 1;
        size = 300;
    }
    else if (nImg == 2)
    {
        w = 2;
        h = 1;
        size = 300;
    }
    else if (nImg == 3 || nImg == 4)
    {
        w = 2;
        h = 2;
        size = 300;
    }
    else if (nImg == 5 || nImg == 6)
    {
        w = 3;
        h = 2;
        size = 200;
    }
    else if (nImg == 7 || nImg == 8)
    {
        w = 4;
        h = 2;
        size = 200;
    }
    else
    {
        w = 4;
        h = 3;
        size = 150;
    }
    // end of code-block #1
    Mat dispayImage = Mat::zeros(Size(100 + size*w, 60 + size*h), CV_8UC3);

    for (int i= 0, m=20, n=20; i <nImg; i++, m+=(20+size))
    {
        x = images[i].cols;
        y = images[i].rows;

        max = ( x > y ) ? x : y;
        scale = (float) ( (float) max / size );

        if ( i%w == 0 && m != 20 )
        {
            m = 20;
            n += 20 + size;
        }

        Mat imageROI = dispayImage( Rect( m, n, (int)( x / scale ), (int)( y / scale )));
        resize( images[i], imageROI, Size((int)( x / scale ), (int)( y / scale )));
    }

    imshow( winName, dispayImage );
    return 0;
}

i think the part marked as code-block #1 should be replaced with more robust code.

any suggestion and contribution is welcome

EDIT

I found a simple way to replace the block #1

int w = images.size() == 2 ? 2 : cvCeil( sqrt( images.size() ));
int h = cvRound( sqrt( images.size() ));
int size = images.size() <= 2 ? 300 : 300 / w * 2;

github link

edit retag flag offensive close merge delete

Comments

2

Using switch case will be more beautiful

thdrksdfthmn gravatar imagethdrksdfthmn ( 2016-01-08 06:45:20 -0600 )edit
1

Why not make w, h and size parameters input variables and let the user decide. I find it quite useless whenever I see stuff like that being auto calculated using some weird rule or using predefined values. Give the user more freedom by generalizing the sample.

StevenPuttemans gravatar imageStevenPuttemans ( 2016-01-11 08:51:11 -0600 )edit
1

yes. your suggestions were on my todo list :)

sturkmen gravatar imagesturkmen ( 2016-01-11 09:05:02 -0600 )edit
1

oh, sorry i misunderstood your comment. i did not think it before.

sturkmen gravatar imagesturkmen ( 2016-01-11 09:12:22 -0600 )edit

Haha great :D

StevenPuttemans gravatar imageStevenPuttemans ( 2016-01-11 09:15:11 -0600 )edit

I thought before like

int showManyImages( const String winName, const vector<Mat> images, Size displayImageSize, int border_width = 0 );

it could be like below taking your idea ( if parameter is 0 will be calculated internally)

int showManyImages( const String winName, const vector<Mat> images, Size displayImageSize, int border_width = 0, int row_count = 0 );
sturkmen gravatar imagesturkmen ( 2016-01-11 09:30:13 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
4

answered 2016-01-11 07:47:46 -0600

Kellerspeicher gravatar image
  • ceil( sqrt(2) ) == 2 so there is no need for ? :.
  • sqrt() is an expensive function and not needed twice.
  • be careful with operator order better use brackets or unambiguous order

Your should (not tested) get the same with:

int w = cvCeil( sqrt( ( double )( images.size() ) ) );
int h = cvCeil( ( double )( images.size() ) / w );
int size = images.size() <= 2 ? 300 : 2 * 300 / w;

But you will not get the same result as your original code e.g. images.size() == 7 results in w == 3 not w == 4. Having such a limited number of cases (12) the fastest and most flexible method are lookup tables:

static const int wl[] = { 0,1,2,2,2,3,3,3,3,3,4,4,4 };
static conat int hl[] = { 0,1,1,2,2,2,2,3,3,3,3,3,3 };
static const int sl[] = { 0,300,300,200,150 };
int w = wl[n];
int h = hl[n];
int size = sl[w];

But take care of being consistent. Lookup tables do also offer many ways to create faults.

edit flag offensive delete link more

Comments

thank you for your answer. it is not necessary to be dependant on older code. i know still must do some corrections when i have time

sturkmen gravatar imagesturkmen ( 2016-01-11 08:01:55 -0600 )edit

Question Tools

Stats

Asked: 2016-01-08 04:35:09 -0600

Seen: 825 times

Last updated: Jan 11 '16