4

I need to draw a transparent image over the live camera feed. The below is the png file to be shown as overlay over the camera feed.

Circle image as overlay over the camera window

The below is the piece of code to fetch the frames from camera and show it on screen. I also tried to draw the circle as overlay, but the circle is not transparent. I think am wrong or missing out something in the below piece of code?

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

int main () {

 Mat src;
 Mat overlay = imread ( "circle.png", -1 );

 VideoCapture cap ( 0 );

 while ( 1 ) {

 cap >> src;
 cvtColor( src, src, CV_BGR2BGRA );
 overlay.copyTo( src.colRange(0,400).rowRange(0,400));
 imshow ( "src",src );
 waitKey( 10 );

 }

 return 0;
 }
ely
  • 74,674
  • 34
  • 147
  • 228
user2727765
  • 616
  • 1
  • 12
  • 28
  • hey, that won't be so easy. why don't you just *draw* an [ellipse](http://docs.opencv.org/modules/core/doc/drawing_functions.html#ellipse) instead ? – berak Jan 06 '14 at 19:31
  • make sure the circle have a proper alpha channel (value 255) for its white regions.. also add if & break statements around `waitKey`. – baci Jan 06 '14 at 19:33
  • @berak its just an example.. I need to draw another image over the cmara feed instead of ellipse. – user2727765 Jan 06 '14 at 19:41
  • your current code just replaces one image with another, alpha or not. ther's no operation in opencv, that honours alpha, so you've got to improvise, like taking the inverse of the alpha channel as a mask for the add() operation. again, it's a computer-vision library, not meant to stick funny moustaches on ppls faces. – berak Jan 06 '14 at 19:57
  • 1
    @berak finally this works http://jepsonsblog.blogspot.in/2012/10/overlay-transparent-image-in-opencv.html – user2727765 Jan 07 '14 at 05:56

2 Answers2

3

If your overlay image has an alpha channel (and assuming the images are of the same size) you can do something like that

cv::Mat display_img( src.size(), src.type() );
for (int y = 0; y < src.rows; y++)
{
    const cv::Vec3b* src_pixel = src.ptr<cv::Vec3b>(y);
    const cv::Vec4b* ovl_pixel = overlay.ptr<cv::Vec4b>(y);
    cv::Vec3b* dst_pixel = display_img.ptr<cv::Vec3b>(y);
    for (int x = 0; x < src.cols; x++, ++src_pixel, ++ovl_pixel, ++dst_pixel)
    {
        double alpha = (*ovl_pixel).val[3] / 255.0;
        for (int c = 0; c < 3; c++)
        {
            (*dst_pixel).val[c] = (uchar) ((*ovl_pixel).val[c] * alpha + (*src_pixel).val[c] * (1.0 -alpha));
        }
    }
}
Rosa Gronchi
  • 1,828
  • 15
  • 25
2

I just solved exactly the same problem, my solution was to figure out which pixels in the overlay have something in them and zero out those pixels in the image. Now you know that every pixel is zero in one of the two images, then you can just add the two images together.

in python:

import numpy as np
import cv2

# load the overlay file
overlay = cv2.imread('overlay.png')

# detect which pixels in the overlay have something in them
# and make a binary mask out of it
overlayMask = cv2.cvtColor( overlay, cv2.COLOR_BGR2GRAY )
res, overlayMask = cv2.threshold( overlayMask, 10, 1, cv2.THRESH_BINARY_INV)

# expand the mask from 1-channel to 3-channel
h,w = overlayMask.shape
overlayMask = np.repeat( overlayMask, 3).reshape( (h,w,3) )


# here's where the work gets done :

# mask out the pixels that you want to overlay
img *= overlayMask

# put the overlay on
img += overlay

# Show the image.
cv2.imshow(WINDOW_NAME, img)
Mike Ounsworth
  • 2,444
  • 21
  • 28