Image watermarking on specific position in an image in python - python

Currently I am working with an image processing project in which I need to split the image into several segments and then apply watermark on each of the segment.
I have written a code which divides the image into segments by masking. You may find the code here. Now i want to implement watermark on each of these segments. The tutorial for watermarking can be found here.
How am I supposed to do that?
Please help as I am new to OpenCV and Python.
Feel free to ask for any further information needed to solve this.
Thank you!
EDIT
I am adding some code for your inference:
`
segment= 'segment storing location'
image = cv2.imread(image path)
segments = slic(img_as_float(image),compactness= 100.0, n_segments = 10, sigma = 5) #segmentation of image
row, col, _ = image.shape
for (i, segVal) in enumerate(np.unique(segments)):
# construct a mask for the segment
print "[x] inspecting segment %d" % (i)
mask = np.zeros(image.shape[:2], dtype = "uint8")
mask[segments == segVal] = 255 #masking image with different mask to create unique segments
bb= (cv2.bitwise_and(image, image, mask = mask) )
cv2.imwrite(segment + str(i) + ".png",bb) #save image segments created
`
Now after saving the segments, I need to watermark each one of them by calling them one after another. This is the code for watermarking:
import numpy as np
import cv2
import os
wk= 'D:\\watermark\\wm.png'
input_im= 'D:\\watermark\\input\\image_01.jpg'
op= 'D:\\watermark\\output'
alpha = 0.25
watermark = cv2.imread(wk, cv2.IMREAD_UNCHANGED)
(wH, wW) = watermark.shape[:2]
image = cv2.imread(input_im)
(h, w) = image.shape[:2]
image = np.dstack([image, np.ones((h, w), dtype="uint8") * 255])
overlay = np.zeros((h, w, 4), dtype="uint8")
overlay[h - wH - 500:h - 500, w - wW - 500:w - 500] = watermark #This is the line where we can set the watermark's coordinates
output = image.copy()
cv2.addWeighted(overlay,alpha, output, 1.0, 0, output)
filename = input_im[input_im.rfind(os.path.sep) + 1:]
p = os.path.sep.join((op, filename))
cv2.imwrite(p, output)
Now how can I extract the coordinates of this segment in order to watermark it?
Edit
This is what I get when the lines
`cv2.circle(im, (cX, cY), 7, (255, 255, 255), -1)
cv2.putText(im, "center", (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2`
are kept outside the loop:
And this is what I get when they are executed within the loop:

You need to find the countour of the image (I've downloaded your segment image to try this), then compute the center of the contour.
To find the contour, you need to convert the image to gray scale and threshold it, dividing totally black pixels (black background) from non-black ones (your segment).
Finding the center of the segment
The only assumption I've made is that the pixel values of your segments are different from 0 (total black). This assumption may be invalid but, since you're working with photos of natural landscape (like the one you posted) this should not be a problem.
Feel free to ask for further details.
import numpy as np
import cv2
im = cv2.imread('try.png')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,1,255,0) # Threshold to highlight non black pixels
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# compute the center of the contour
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw the contour and center of the shape on the image
cv2.drawContours(im, [c], -1, (0, 255, 0), 2)
cv2.circle(im, (cX, cY), 7, (255, 255, 255), -1)
cv2.putText(im, "center", (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
# show the image
cv2.imshow("Image", im)
cv2.waitKey(0)
This is what I get:
Placing the watermark
Let's say you have the coordinates of the center of the segment region. Knowing the size of the watermark you can convert them coordinates locating the point of the image where to put the left upper corner of the watermark. In this example I assume that them are (x=10,y=10).
I've reused the last image you posted (I'm not drawing the contours, just the watermark).
import numpy as np
import cv2 as cv
# Coordinates where to put the watermark (left upper corner)
cy = 10
cx = 10
# Reading the image
image = cv.imread("try.png")
(h,w) = image.shape[:2]
image = np.dstack([image, np.ones((h, w), dtype="uint8") * 255])
# Reading the watermark
watermark = cv.imread("watermark.png", cv.IMREAD_UNCHANGED)
(wH, wW) = watermark.shape[:2]
(B, G, R, A) = cv.split(watermark)
B = cv.bitwise_and(B, B, mask=A)
G = cv.bitwise_and(G, G, mask=A)
R = cv.bitwise_and(R, R, mask=A)
watermark = cv.merge([B, G, R, A])
# Creating the image's overlay with the watermark
overlay = np.zeros((h, w, 4), dtype="uint8")
overlay[cy:wH + cy, cx:wW + cx] = watermark
# Applying the overlay
output = image.copy()
cv.addWeighted(overlay, 0.4, output, 1.0, 0, output)
cv.imshow("out", output)
cv.waitKey()

Related

detect coordinates of black squares and crop image based on these coordinates

I am trying to crop this image by detecting coordinates of pitch black squares on the upper side, tick marked in this image one I detect coordinates I need to crop image in straight lines to these coordinates as mentioned in this image and only keep inner area. I have tried following code to detect coordinates of contours
import numpy as np
import cv2
# Reading image
font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread("img.jpg", cv2.IMREAD_COLOR)
# Reading same image in another
# variable and converting to gray scale.
img = cv2.imread("img.jpg", cv2.IMREAD_GRAYSCALE)
# Converting image to a binary image
# ( black and white only image).
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
# Detecting contours in image.
contours, _= cv2.findContours(threshold, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
# Going through every contours found in the image.
for cnt in contours :
approx = cv2.approxPolyDP(cnt, 0.009 * cv2.arcLength(cnt, True), True)
# draws boundary of contours.
cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
# Used to flatted the array containing
# the co-ordinates of the vertices.
n = approx.ravel()
i = 0
for j in n :
if(i % 2 == 0):
x = n[i]
y = n[i + 1]
# String containing the co-ordinates.
string = str(x) + " " + str(y)
if(i == 0):
# text on topmost co-ordinate.
cv2.putText(img2, "Arrow tip", (x, y),
font, 0.5, (255, 0, 0))
else:
# text on remaining co-ordinates.
cv2.putText(img2, string, (x, y),
font, 0.5, (0, 255, 0))
i = i + 1
cv2.imwrite('img.jpg', img2)
but it isn't detecting coordinates properly as you can see here can someone suggest me what am I doing wrong here? Thank you

Rotating QR code to the correct position using Python OpenCV

I'm a beginner in python and currently studying QR code detection and decoding. I'm having a hard time rotating the detected QR code to the right position. I already used minAreaRect() to rotate my QR code but it doesn't work. Is there any workaround or a right way to do this? thanks!
ROI2 = cv2.imread('ROI.png')
gray2 = cv2.cvtColor(ROI2, cv2.COLOR_BGR2GRAY)
blur2 = cv2.GaussianBlur(gray2, (9, 9), 0)
thresh2 = cv2.threshold(blur2, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Morph close
# kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# close2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel2, iterations=10)
# Find contours and filter for QR code
cnts2 = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts2 = cnts2[0] if len(cnts2) == 2 else cnts2[1]
c = sorted(cnts2, key=cv2.contourArea, reverse=True)[0]
draw = cv2.cvtColor(thresh2, cv2.COLOR_GRAY2BGR)
cv2.drawContours(draw, [c], 0, (0, 255, 0), 2)
rotrect = cv2.minAreaRect(c)
box = cv2.boxPoints(rotrect)
box = numpy.int0(box)
cv2.drawContours(draw, [box], 0, (0, 0, 255), 2)
cv2.imshow('thresh', thresh2)
cv2.imshow('ROI', ROI2)
cv2.imshow('minarearect', draw)
From my understanding, you're trying to deskew an image. To do this, we need to first compute the rotated bounding box angle then perform a linear transformation. The idea is to use
cv2.minAreaRect + cv2.warpAffine. According to the documentation, cv2.minAreaRect returns
(center(x, y), (width, height), angle of rotation) = cv2.minAreaRect(...)
The third parameter gives us the angle we need to deskew the image.
Input image -> Output result
Skew angle: -39.99416732788086
Code
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('2.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Compute rotated bounding box
coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
print("Skew angle: ", angle)
# Rotate image to deskew
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
cv2.imshow('rotated', rotated)
cv2.waitKey()
Note: See Python OpenCV skew correction for another approach using the Projection Profile Method to correct skew.
Detect the code using QRCodeDetector::detectAndDecode and redraw it from the straight_qrcode value. The QRCodeDetector might not be able to decode all codes that you can locate using simple thresholding and contours. Especially when pieces of it are missing (including the quiet zone), the QR code detector might have trouble.
This will always show the code in its canonical orientation, with the finder patterns to the NW, NE, and SW directions.
Simple minAreaRect will only align the code's edges to the image axes, but it would not be able to tell which way is "up" in the QR code.
import cv2 as cv
im = cv.imread("OnDlO.png")
det = cv.QRCodeDetector()
(rv, points, straight_qrcode) = det.detectAndDecode(im)
# rv == 'testing123456'
# points:
# array([[[304. , 36. ],
# [415. , 321. ],
# [141.55959, 428.3963 ],
# [ 32. , 151. ]]], dtype=float32)
# some white padding
with_quiet_zone = cv.copyMakeBorder(straight_qrcode, 1, 1, 1, 1, borderType=cv.BORDER_CONSTANT, value=255)
# scale it up for display
larger = cv.resize(with_quiet_zone, dsize=None, fx=16, fy=16, interpolation=cv.INTER_NEAREST)
# and show it
cv.imshow("larger", larger)
cv.waitKey()
input:
output:

Finding the coordinates of the edges on a rectangluar object

I am trying to build a document scanner application from scratch using OpenCV and python. Till now i have done the following:
re-scaled the image
preprocessed the image, that is converted to greyscale, applied the Gaussian blur, applied adaptive threshold and finally used canny edge detection.
I then found the largest contour and drew it
Detected the edges of the contour and drew them
step 4 is where the problem is, I'm getting two of the points in the correct location however two seem to be slightly offset.
I can't seem to understand what I'm doing wrong, additionally could this problem potentially be due to the way i have preprocessed the image?
import cv2
import numpy as np
# Function to resize the image
def Re_scaleImg(img):
scale_percent = 50
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
# resize the image
resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
return resized
# Function to process the image
def process(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
edged = cv2.Canny(thresh, 75, 200)
#cv2.imshow("blur", blur)
#cv2.imshow("edged", thresh)
return edged
# Function to find the areas of contours
def find_contourArea(contours):
areas = []
for cnt in contours:
cont_area = cv2.contourArea(cnt)
areas.append(cont_area)
return areas
image = cv2.imread("receipt.jpeg")
resized = Re_scaleImg(image)
processed_img = process(resized)
# finding the contours
contours, hierarchy = cv2.findContours(processed_img.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
resized_copy1 = resized.copy()
# sorting the contours
sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)
largest_contour = sorted_contours[0]
epsilon = 0.01*cv2.arcLength(largest_contour, True)
approximation = cv2.approxPolyDP(largest_contour, epsilon, True)
cv2.drawContours(resized_copy1, [approximation], -1, (0, 255, 0), 3)
# Obtaining the corners of the rectangle
rot_rect = cv2.minAreaRect(largest_contour)
box = cv2.boxPoints(rot_rect)
box = np.int0(box)
for p in box:
pt = (p[0], p[1])
cv2.circle(resized_copy1, pt, 10, (255, 0, 0), -1)
print(pt)
cv2.imshow("contours", resized_copy1)
cv2.waitKey(0)
Both the images are shown below:
the original image:
output image:
Instead of finding the full contour are you could try to find the lines on the edge of the document instead.
With the Hough Line Transform you can find the four most prominent lines (with the most votes).
From these lines you can then calculate the intersection points and use the four points closes to the center of the full shape as corner points.

Python OpenCV - Extrapolating the largest rectangle off of a set of contour points

I'm trying to make an OpenCV detect a bed in the image. I am running the usual Grayscale, Blur, Canny, and I've tried Convex Hull. However, since there's quite a number of "noise" which gives extra contours and messes up the object detection. Because of this, I am unable to detect the bed properly.
Here is the input image as well as the Canny Edge Detection result:
As you can see, it's almost there. I have the outline of the bed already, albeit, that the upper right corner has a gap - which is preventing me from detecting a closed rectangle.
Here's the code I'm running:
import cv2
import numpy as np
def contoursConvexHull(contours):
print("contours length = ", len(contours))
print("contours length of first item = ", len(contours[1]))
pts = []
for i in range(0, len(contours)):
for j in range(0, len(contours[i])):
pts.append(contours[i][j])
pts = np.array(pts)
result = cv2.convexHull(pts)
print(len(result))
return result
def auto_canny(image, sigma = 0.35):
# compute the mediam of the single channel pixel intensities
v = np.median(image)
# apply automatic Canny edge detection using the computed median
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) *v))
edged = cv2.Canny(image, lower, upper)
# return edged image
return edged
# Get our image in color mode (1)
src = cv2.imread("bed_cv.jpg", 1)
# Convert the color from BGR to Gray
srcGray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# Use Gaussian Blur
srcBlur = cv2.GaussianBlur(srcGray, (3, 3), 0)
# ret is the returned value, otsu is an image
##ret, otsu = cv2.threshold(srcBlur, 0, 255,
## cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Use canny
##srcCanny = cv2.Canny(srcBlur, ret, ret*2, 3)
srcCanny1 = auto_canny(srcBlur, 0.70)
# im is the output image
# contours is the contour list
# I forgot what hierarchy was
im, contours, hierarchy = cv2.findContours(srcCanny1,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
##cv2.drawContours(src, contours, -1, (0, 255, 0), 3)
ConvexHullPoints = contoursConvexHull(contours)
##cv2.polylines(src, [ConvexHullPoints], True, (0, 0, 255), 3)
cv2.imshow("Source", src)
cv2.imshow("Canny1", srcCanny1)
cv2.waitKey(0)
Since the contour of the bed isn't closed, I can't fit a rectangle nor detect the contour with the largest area.
The solution I can think of is to extrapolate the largest possible rectangle using the contour points in the hopes of bridging that small gap, but I'm not too sure how to proceed since the rectangle is incomplete.
Since you haven't provided any other examples, I provide an algorithm working with this case. But bare in mind that you will have to find ways of adapting it to however the light and background changes on other samples.
Since there is a lot of noise and a relatively high dynamic range, I suggest not to use Canny and instead use Adaptive Thresholding and Find Contours on that (it doesn't need edges as an input), that helps with choosing different threshold values for different parts of the image.
My result:
Code:
import cv2
import numpy as np
def clahe(img, clip_limit=2.0, grid_size=(8,8)):
clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=grid_size)
return clahe.apply(img)
src = cv2.imread("bed.png")
# HSV thresholding to get rid of as much background as possible
hsv = cv2.cvtColor(src.copy(), cv2.COLOR_BGR2HSV)
lower_blue = np.array([0, 0, 120])
upper_blue = np.array([180, 38, 255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
result = cv2.bitwise_and(src, src, mask=mask)
b, g, r = cv2.split(result)
g = clahe(g, 5, (3, 3))
# Adaptive Thresholding to isolate the bed
img_blur = cv2.blur(g, (9, 9))
img_th = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 51, 2)
im, contours, hierarchy = cv2.findContours(img_th,
cv2.RETR_CCOMP,
cv2.CHAIN_APPROX_SIMPLE)
# Filter the rectangle by choosing only the big ones
# and choose the brightest rectangle as the bed
max_brightness = 0
canvas = src.copy()
for cnt in contours:
rect = cv2.boundingRect(cnt)
x, y, w, h = rect
if w*h > 40000:
mask = np.zeros(src.shape, np.uint8)
mask[y:y+h, x:x+w] = src[y:y+h, x:x+w]
brightness = np.sum(mask)
if brightness > max_brightness:
brightest_rectangle = rect
max_brightness = brightness
cv2.imshow("mask", mask)
cv2.waitKey(0)
x, y, w, h = brightest_rectangle
cv2.rectangle(canvas, (x, y), (x+w, y+h), (0, 255, 0), 1)
cv2.imshow("canvas", canvas)
cv2.imwrite("result.jpg", canvas)
cv2.waitKey(0)

Select object by color in an image?

Is there a way to find object that have specific color (for example red rectangle 100px 50px with white text) and then select that object as it is and cut it to new file? Look at the picture below. I'm trying to make a script for selecting data from image, then convert to text and finally write to Excel.
I googled a lot of howtos but didn't find any that address my problem.
Sample image
I don't know your real intention, would you like only read the text or do you like also extract the parts?
Anyway, I'm going to show you a straight forward and general solution. Take the parts you need, at the end you find the hole code.
For the hole bunch you need 4 modules:
cv2 (openCV) for image processing
numpy to handle special operations on the images
pytesseract to recognize text (ocr)
pillow (pil) to prepare the image for pytesseract
Load und filter
Your original image:
First we reduce all colors except red. lower and upper describes the values from BGR (RGB = red, green, blue) we like to filter.
image = cv.imread("AR87t.jpg")
lower = np.array([0, 0, 200])
upper = np.array([100, 100, 255])
shapeMask = cv.inRange(image, lower, upper)
cv.imshow("obj shapeMask", shapeMask)
cv.waitKey(0)
This shows:
finding contours
Next, we find the contours and iterating through. If we find 4 corners, we will do the next stuff...
cnts = cv.findContours(shapeMask.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)[0]
for c in cnts:
peri = cv.arcLength(c, True)
approx = cv.approxPolyDP(c, 0.04 * peri, True)
if len(approx) == 4:
....
mask the original
With boundingRect, we extract x, y, w, h
(x, y, w, h) = cv.boundingRect(approx)
cv.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), thickness=5)
ocr on the mask
And here comes the magic! First we extract the mask parts and export the openCV image to an PIL image. We are then able to run tesseract over.
el = shapeMask.copy()[y:y + h, x:x + w]
pil_im = Image.fromarray(el)
cv.imshow("obj", el)
cv.waitKey(0)
print(pytesseract.image_to_string(pil_im))
this shows you every rectangle as small image. You console will print out:
L2 = 33,33
L3 = 44,44
L1 = 12,22
code
import cv2 as cv
import numpy as np
import pytesseract
from PIL import Image
image = cv.imread("AR87t.jpg")
lower = np.array([0, 0, 200])
upper = np.array([100, 100, 255])
shapeMask = cv.inRange(image, lower, upper)
cv.imshow("obj shapeMask", shapeMask)
cv.waitKey(0)
cnts = cv.findContours(shapeMask.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)[0]
for c in cnts:
peri = cv.arcLength(c, True)
approx = cv.approxPolyDP(c, 0.04 * peri, True)
if len(approx) == 4:
(x, y, w, h) = cv.boundingRect(approx)
cv.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), thickness=5)
print("w:%s, y:%s, w:%s, h:%s" % (x, y, w, h))
el = shapeMask.copy()[y:y + h, x:x + w]
pil_im = Image.fromarray(el)
cv.imshow("obj", el)
cv.waitKey(0)
print(pytesseract.image_to_string(pil_im))
cv.imshow("obj rectangle", image)
cv.waitKey(0)

Categories