0

Here is a sample image of signature :

sample

How to get the signature from this image without background so that I can paste it over user image. What if background is not white?

I have tried this, how to customize it for different background colors?

Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
Karan Kanwal
  • 29
  • 1
  • 10

3 Answers3

3

Just started with Python myself but thought I'd have a go at a solution - came up with this:

#!/usr/bin/python2

import cv2
import numpy as np

file_name = "/tmp/signature.jpg" # your signature image...

image = cv2.imread(file_name, 1)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGBA)
# note: [R,G,B,255] below, so first 3 numbers [255,255,255] are your white 
# background pixels to be converted to RGBA setting of [0,0,0,0] (transparent)
image[np.all(image == [255, 255, 255, 255], axis=2)] = [0, 0, 0, 0]

cv2.imwrite("/tmp/signature-transparent.png", image)

This script will grab your signature.jpg, make a transparent background from all the white pixels it finds, then write it to signature.png.

Looks like this:

transparent background image

However it's not exactly clean around the edges! Anyone out there who can sort that?

renedv1
  • 131
  • 3
1

It is quite a process, mainly because there are a number of steps to add an image on top of an image of a different size. I advice you to check out all intermediate steps in the code below, to understand what happens.

I used the HSV-colorspace to separate the signature from the background, this is easy to adapt if the signature or background have other colors.

I have not found python bindings for the copyTo()-method used by @BahramdunAdil. You could use numpy.copyto() functionality instead. For that I'll refer you to this answer.

I used a different technique: to add the image on top of another, first a subimage of the same size as the signature is created. The signature can be added to the subimage, which is then put back in the main image.

Alternatively, you can take the thresholded signature and use @renedv1's method to save an alpha image. Use the sign_masked image for that. Because of the HSV-range you can create a cleaner result. (Note: account for the fact that sign_masked has a black background)

Result:
enter image description here

Code:

    import numpy as np 
    import cv2
    # load image
    sign = cv2.imread("sign.jpg")
    bg_img = cv2.imread("green_area.jpg")

     # Convert BGR to HSV
    hsv = cv2.cvtColor(sign, cv2.COLOR_BGR2HSV)

    # define range of HSV-color of the signature
    lower_val = np.array([0,0,0])
    upper_val = np.array([179,255,150])

    # Threshold the HSV image to get a mask that holds the signature area
    mask = cv2.inRange(hsv, lower_val, upper_val)
    # create an opposite: a mask that holds the background area
    mask_inv= cv2.bitwise_not(mask)

    # create an image of the signature with background excluded
    sign_masked = cv2.bitwise_and(sign,sign,mask=mask)

    # get the dimensions of the signature
    height, width = sign.shape[:2]

    # create a subimage of the area where the signature needs to go
    placeToPutSign = bg_img[0:height,0:width]
    # exclude signature area 
    placeToPutSign_masked = cv2.bitwise_and(placeToPutSign, placeToPutSign, mask=mask_inv)
    # add signature to subimage
    placeToPutSign_joined = cv2.add(placeToPutSign_masked, sign_masked)

    # put subimage over main image
    bg_img[0:height,0:width] = placeToPutSign_joined

    # display image
    cv2.imshow("result", bg_img)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
J.D.
  • 4,511
  • 2
  • 7
  • 20
  • It is not `toCopy` it is `copyTo()` or `cv::copyTo()`, all the functions in C++ are exist in Python, OpenCV is written in C++ and provide a wrapper to Python. – Bahramdun Adil Mar 05 '19 at 11:55
  • That is indeed what I would expect. However, I have found no example or documentation of it. The answer to a similar question [here](https://stackoverflow.com/a/51458447/10699171) also states that no python bindings were found. In that answer `numpy.copyto()` is used instead. I will update my answer to clarify. If you do know the bindings in opencv I would like to know :) – J.D. Mar 05 '19 at 12:44
  • It is not a function of numpy, it is a function of Mat data type of the OpenCV, you can see the code on what object I have used `copyTo()`, but yes there is no `toCopy()` function as you mentioned above, you may be wrong in spelling, you check it carefully. – Bahramdun Adil Mar 05 '19 at 12:48
  • It is the documentation: https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#ab931fe25e359c1fe727e526aa5693ea9 – Bahramdun Adil Mar 05 '19 at 12:50
  • Yes, I know it exists for c++. However, I does not appear to exist for python - even though you would expect it. I tried several things based on the documentation, all give an error stating it doesn't exist. Googling for 'opencv python copyto' gives nothing useful, only links to c++ code. Like I said, in the answer I refer to (from july 2018) is also stated that no bindings were found, so it's not just me. This may be a (unknown / unwanted?) difference between c++ / python. However, I you know or can find a working code example of `copyto` in python, please share. – J.D. Mar 05 '19 at 13:22
  • Hmmm, It may be lack of API OpenCV to Python wrapper, but copyTo() is a very impotent function. – Bahramdun Adil Mar 05 '19 at 13:48
0

You should consider the steps below: for example, pretend it is your user image:

enter image description here

Now go with these steps:

cv::namedWindow("result", cv::WINDOW_FREERATIO);
cv::Mat signatureImg = cv::imread(R"(izrMq.jpg)");
cv::Mat userImg = cv::imread(R"(user_image.jpg)");

// make a mask
cv::Mat mask;
cv::cvtColor(signatureImg, mask, cv::COLOR_BGR2GRAY);
cv::threshold(mask, mask, 150, 255, cv::THRESH_BINARY_INV);

// now copy
cv::Mat submat = userImg(cv::Rect(userImg.cols-signatureImg.cols, userImg.rows-signatureImg.rows, signatureImg.cols, signatureImg.rows));
signatureImg.copyTo(submat, mask);

cv::imshow("result", userImg);

cv::waitKey();

And it is the result:

enter image description here

Hope it helps!

Bahramdun Adil
  • 5,907
  • 7
  • 35
  • 68