Ask Your Question
3

How to speed up seamlessClone? (incredibly slow)

asked 2015-07-22 10:08:30 -0600

Fragender gravatar image

Hi,

I am using seamlessClone to integrate a logo into a video and it is incredibly slow. Actually creating a video with 1000 frames with a resolution of 1280 x 800 takes 30 seconds. While using seamlessClone it takes round about 15 seconds to write one single frame!

I am not sure whether I use this function in a wrong way or whether seamlessClone is really that heavy.

This is basically what I do:

int main() {
cv::Mat logo= imread("logo.png", CV_LOAD_IMAGE_COLOR);

Size size(100,120);
Mat LogoResized;
resize(logo,LogoResized,size);
Point center(300,300);

Mat mask_forCloning = 255 * Mat::ones(LogoResized.rows, LogoResized.cols, LogoResized.depth());
Mat normal_clone;
Mat image;

for (int i=0; i<1000; i++)
{
    image = imread(pictureName, CV_LOAD_IMAGE_COLOR);  //Of course the name is changing with every frame ;-)

seamlessClone(LogoResized, image, mask_forCloning, center, normal_clone, NORMAL_CLONE);

writeCurrentFrameToVideo(normal_clone);
}

}

Is there a possibility to speed this up?

Thank you very much :-)

edit retag flag offensive close merge delete

Comments

let me try some other way if you share your logo. ( or any png having same characteristic)

sturkmen gravatar imagesturkmen ( 2015-08-05 05:00:22 -0600 )edit

Hi, thank you very much. Due to rights I cannot provide you the original logo, but the following has the same characteristics and I just tested the cloning with it. It is comparable slow like with the logo I use. Image

Thanks a lot :-)

Fragender gravatar imageFragender ( 2015-08-05 06:40:14 -0600 )edit

2 answers

Sort by » oldest newest most voted
2

answered 2015-08-05 18:33:09 -0600

updated 2015-08-05 19:04:00 -0600

with the code below i tried to achive desired result instead of using cv::seamlessClone. i hope it helps.

references:

http://answers.opencv.org/question/1 @Alexander Shishkov

http://answers.opencv.org/question/21686 @berak

http://answers.opencv.org/question/37568 Martin Peris

thanks all.

used image opencv-logo-150.png

#include "opencv2/opencv.hpp"

using namespace cv;

int main(int argc, char** argv)
{
    VideoCapture cap(0);

    if(!cap.open(0))
        return 0;

    int x, y;
    x = 100;
    y = 100;

    Mat mask;
    Mat c[4];

    Mat logo= imread("opencv-logo-150.png", -1);
    //Mat logo= imread("bmp.bmp", -1); // must have white background

    Size nsize(logo.cols / 2, logo.rows / 2);

    resize(logo,logo,nsize,0,0,INTER_NEAREST);
    //resize(logo,logo,nsize,0,0,INTER_LINEAR);
    //resize(logo,logo,nsize,0,0,INTER_CUBIC);
    //resize(logo,logo,nsize,0,0,INTER_AREA);
    //resize(logo,logo,nsize,0,0,INTER_LANCZOS4);


    if(logo.channels()==4)
    {
        split(logo,c);         // seperate channels
        Mat cs[3] = { c[0],c[1],c[2] };
        merge(cs,3,logo);  // glue together again
        mask = c[3];       // png's alpha channel used as mask
    }
    else
    {
    cvtColor( logo, mask, COLOR_BGR2GRAY );
    mask = mask < 255;
    }


    for(;;)
    {
        Mat frame;

        cap >> frame;
        if( frame.empty() ) break; // end of video stream

        logo.copyTo(frame(cv::Rect(x,y,logo.cols, logo.rows)),mask);

        imshow("VideoCapture", frame);
        if( waitKey(1) == 27 ) break; // stop capturing by pressing ESC
    }

    return 0;
}
edit flag offensive delete link more
2

answered 2015-08-07 06:14:48 -0600

Fragender gravatar image

updated 2015-08-07 07:05:56 -0600

Hi sturkmen,

thank you very much for the nice code!

No just the background of the normal seamlessClone is missing.

This can be achieved by increasing the brightness and then blurring.

I just added this code before the logo.copyTo:

    double alpha=1.0; //alpha value [1.0-3.0]
    int beta=70; //beta value [0-100]

    /// Increasing brightness:
    /// Do the operation image(i,j) = alpha*image(i,j) + beta
     for( int y2 = y; y2 < mask.rows+y; y2++ )
        {
         for( int x2 = x; x2 < mask.cols+x; x2++ )
             {
                for( int c = 0; c < 3; c++ )
                  {
                    frame.at<Vec3b>(y2,x2)[c] =
                    saturate_cast<uchar>( alpha*( frame.at<Vec3b>(y2,x2)[c] ) + beta );
                  }
             }
        }
    cv::Rect region (x,y,logo.cols, logo.rows);

    ///Blurring:
    GaussianBlur(frame(region), frame(region), Size(0, 0), 6);


    logo.copyTo(frame(region),mask);

There is just one thing I do not know how to manage. As you can see I used manual values in the first two for loops (mask.rows+100). I do not know where to get the real dimensions of the logo automatically as it is copied using a mask.

Still... the solution works now quite nice :-) Thanks a lot!

edit flag offensive delete link more

Comments

1

your welcome. your addition is good. i made correction to your code as

for( int y2 = y; y2 < mask.rows+y; y2++ ) { for( int x2 = x; x2 < mask.cols+x; x2++ )

sturkmen gravatar imagesturkmen ( 2015-08-07 06:24:50 -0600 )edit
1

a short way to increas brightness instead loop is frame(region).convertTo(frame(region),-1,1,70);

sturkmen gravatar imagesturkmen ( 2015-08-07 09:04:19 -0600 )edit

Thank you very much for the perfect help :-)

Fragender gravatar imageFragender ( 2015-08-11 03:18:21 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-07-22 10:08:30 -0600

Seen: 2,917 times

Last updated: Aug 07 '15