How to create watermark like shutterstock and Adobe Stock in python - python

I am trying to create a GAN model which will remove watermark. After doing some homework, I got to this Google AI Blog which makes things worse. Thus I need to create a dataset from these websites Shutterstock, Adobe Stock, Fotolia and Canstock and manymore.
So, when I try to do same image using reverse image search. I founded out that the resolutions, images are changed which makes it more worse.
Thus, I'm only left to create a custom dataset doing the same watermark like from these websites and that's why I need to create same watermark like them on images from unsplash and so..
Can anyone please help me create same watermark which we can get from Shutterstock and Adobe Stock. It'd be a great help.
Note: I have gone through this link for watermark using Imagemagick but I need it in python. If someone can show me a way of doing the same in python. That'd be a great help.
EDIT1: If you look at this Example of Shutterstock. Zoom in and you will find that not only lines but text and rounded symbols are curved and also name and rounded symbol with different opacity. So, that's what I want to replicate.

Here is one way to do that in Python/OpenCV.
Read the input
Create an image of the text
Rotate the text image
Tile out the rotated text image to the size of the input
Blend the tiled, rotated text image with the input image
Save the output
Input:
import cv2
import numpy as np
import math
text = "WATERMARK"
thickness = 2
scale = 0.75
pad = 5
angle = -45
blend = 0.25
def rotate_bound(image, angle):
# function to rotate an image
# from https://github.com/PyImageSearch/imutils/blob/master/imutils/convenience.py
# grab the dimensions of the image and then determine the center
(h, w) = image.shape[:2]
(cX, cY) = (w / 2, h / 2)
# grab the rotation matrix (applying the negative of the
# angle to rotate clockwise), then grab the sine and cosine
# (i.e., the rotation components of the matrix)
M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# perform the actual rotation and return the image
return cv2.warpAffine(image, M, (nW, nH))
# read image
photo = cv2.imread('lena.jpg')
ph, pw = photo.shape[:2]
# determine size for text image
(wd, ht), baseLine = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, scale, thickness)
print (wd, ht, baseLine)
# add text to black background image padded all around
pad2 = 2 * pad
text_img = np.zeros((ht+pad2,wd+pad2,3), dtype=np.uint8)
text_img = cv2.putText(text_img, text, (pad,ht+pad), cv2.FONT_HERSHEY_SIMPLEX, scale, (255,255,255), thickness)
# rotate text image
text_rot = rotate_bound(text_img, angle)
th, tw = text_rot.shape[:2]
# tile the rotated text image to the size of the input
xrepeats = math.ceil(pw/tw)
yrepeats = math.ceil(ph/th)
print(yrepeats,xrepeats)
tiled_text = np.tile(text_rot, (yrepeats,xrepeats,1))[0:ph, 0:pw]
# combine the text with the image
result = cv2.addWeighted(photo, 1, tiled_text, blend, 0)
# save results
cv2.imwrite("text_img.png", text_img)
cv2.imwrite("text_img_rot.png", text_rot)
cv2.imwrite("lena_tiled_rotated_text_img.jpg", result)
# show the results
cv2.imshow("text_img", text_img)
cv2.imshow("text_rot", text_rot)
cv2.imshow("tiled_text", tiled_text)
cv2.imshow("result", result)
cv2.waitKey(0)
Text Image:
Rotated Text Image:
Result:

Here is another variation in Python/OpenCV that does outline font for the watermark. I have made the font size larger so that the outline is more visible.
import cv2
import numpy as np
import math
text = "WATERMARK"
thickness = 2
scale = 1.5
pad = 5
angle = -45
blend = 0.4
# function to rotate an image
def rotate_bound(image, angle):
# from https://github.com/PyImageSearch/imutils/blob/master/imutils/convenience.py
# grab the dimensions of the image and then determine the center
(h, w) = image.shape[:2]
(cX, cY) = (w / 2, h / 2)
# grab the rotation matrix (applying the negative of the
# angle to rotate clockwise), then grab the sine and cosine
# (i.e., the rotation components of the matrix)
M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# perform the actual rotation and return the image
return cv2.warpAffine(image, M, (nW, nH))
# read image
photo = cv2.imread('lena.jpg')
ph, pw = photo.shape[:2]
# determine size for text image
(wd, ht), baseLine = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, scale, thickness)
print (wd, ht, baseLine)
# add text to black background image padded all around
# write thicker white text and then write over that with thinner gray text to make outline text
pad2 = 2 * pad
text_img = np.zeros((ht+pad2,wd+pad2,3), dtype=np.uint8)
text_img = cv2.putText(text_img, text, (pad,ht+pad), cv2.FONT_HERSHEY_SIMPLEX, scale, (256,256,256), thickness+3)
text_img = cv2.putText(text_img, text, (pad,ht+pad), cv2.FONT_HERSHEY_SIMPLEX, scale, (128,128,128), thickness)
# rotate text image
text_rot = rotate_bound(text_img, angle)
th, tw = text_rot.shape[:2]
# tile the rotated text image to the size of the input
xrepeats = math.ceil(pw/tw)
yrepeats = math.ceil(ph/th)
print(yrepeats,xrepeats)
tiled_text = np.tile(text_rot, (yrepeats,xrepeats,1))[0:ph, 0:pw]
# combine the text with the image
#result = cv2.addWeighted(photo, 1, tiled_text, blend, 0)
mask = blend * cv2.threshold(tiled_text, 0, 255, cv2.THRESH_BINARY)[1]
result = (mask * tiled_text.astype(np.float64) + (255-mask)*photo.astype(np.float64))/255
result = result.clip(0,255).astype(np.uint8)
# save results
cv2.imwrite("text_img.png", text_img)
cv2.imwrite("text_img_rot.png", text_rot)
cv2.imwrite("lena_tiled_rotated_text_img2.jpg", result)
# show the results
cv2.imshow("text_img", text_img)
cv2.imshow("text_rot", text_rot)
cv2.imshow("tiled_text", tiled_text)
cv2.imshow("result", result)
cv2.waitKey(0)
Result:

Related

How to print text as watermark on images vertically in Python

I Here is my Code
# Json file in which Easyocr anotations have saved.
img = cv2.imread('dummy.jpg')
img1 = img.copy()
#rotoated because anotation have according to vertical alignment of image i have matched the orientation
img1=cv2.rotate(img1,rotateCode=cv2.ROTATE_90_CLOCKWISE)
rects = []
with open('dummy.json') as jsn:
jsn_dict = json.load(jsn)
for k in jsn_dict['textAnnotations']:
vertices= k['boundingPoly']['vertices']
cv2.rectangle(img1,list(vertices[2].values()),list(vertices[0].values()),[0,255,0],10)
# I want to put predicted text on top of bounding boxes vertically because my image is rotated anti clockwise
cv2.putText(img1, k['description'], list(vertices[0].values()),cv2.FONT_HERSHEY_SIMPLEX,5,[0,255,0],5)
I have the code mentioned above I am labelling the recognized text. First step is, I put the image into the OCR model and it returns some values according to the image, in which we have three values for every detected text. These values are the vertex of the bounding box, the text that was recognized, and the accuracy percentage. But my problem is that my image was rotated by the Exif orientation value but cv2 read it as a zero angle and my text is printing horizontally. I want to print text on an image vertically. I have tried so many times but could not resolve my problem. I hope I have explained it well.
Try this one
import cv2
def transparentOverlay(src, overlay, pos=(0, 0), scale=1):
"""
:param src: Input Color Background Image
:param overlay: transparent Image (BGRA)
:param pos: position where the image to be blit.
:param scale : scale factor of transparent image.
:return: Resultant Image
"""
overlay = cv2.resize(overlay, (0, 0), fx=scale, fy=scale)
h, w, _ = overlay.shape # Size of foreground
rows, cols, _ = src.shape # Size of background Image
y, x = pos[0], pos[1] # Position of foreground/overlay image
# loop over all pixels and apply the blending equation
for i in range(h):
for j in range(w):
if x + i >= rows or y + j >= cols:
continue
alpha = float(overlay[i][j][3] / 255.0) # read the alpha channel
src[x + i][y + j] = alpha * overlay[i][j][:3] + (1 - alpha) * src[x + i][y + j]
return src
def addImageWatermark(LogoImage,MainImage,opacity,pos=(10,100),):
opacity = opacity / 100
OriImg = cv2.imread(MainImage, -1)
waterImg = cv2.imread(LogoImage, -1)
tempImg = OriImg.copy()
print(tempImg.shape)
overlay = transparentOverlay(tempImg, waterImg, pos)
output = OriImg.copy()
# apply the overlay
cv2.addWeighted(overlay, opacity, output, 1 - opacity, 0, output)
cv2.imshow('Life2Coding', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
addImageWatermark('./logo.png','./hanif.jpg',100,(10,100))
Rotate your image 90º clockwise, add the text, and rotate the image back to the original.
# Rotate 90º clockwise
img_rot = cv2.rotate(img1 , cv2.ROTATE_90_CLOCKWISE)
# Add your text here, adjusting x and y coordinates to the new orientation.
# The new adjusted coordinates will be:
# (x2, y2) = (original_height - y, x)
# [...]
# Rotate back
img1 = cv2.rotate(img_rot, cv2.ROTATE_90_CLOCKWISE)

How to find where a pixel maps to in cv2.resize?

I was wondering, given the type of interpolation that is used for image resizes using cv2.resize. How can I find out exactly where a particular pixel maps too? For example, if I'm increasing the size of an image using Linear_interpolation and I take coordinates (785, 251) for a particular pixel, regardless of whether or not the aspect ratio changes between the source image and resized image, how could I find out exactly to what coordinates the pixel in the source image with coordinates == (785, 251) maps in the resized version? I've looked over the internet for a solution but all solutions seem to be indirect methods of finding out where a pixel maps that don't actually work for different aspect ratio's:
https://answers.opencv.org/question/209827/resize-and-remap/
After resizing an image with cv2, how to get the new bounding box coordinate
Is there a way through cv2 to access the way pixels are mapped maybe and through reversing the script finding out the new coordinates?
The reason why I would like this is that I want to be able to create bounding boxes that give me back the same information regardless of the change in aspect ratio of a given image. Every method I've used so far doesn't give me back the same information. I figure that if I can figure out where the particular pixel coordinates of x,y top left and bottom right maps I can recreate an accurate bounding box regardless of aspect ratio changes.
Scaling the coordinates works when the center coordinate is (0, 0).
You may compute x_scaled and y_scaled as follows:
Subtract x_original_center and y_original_center from x_original and y_original.
After subtraction, (0, 0) is the "new center".
Scale the "zero centered" coordinates by scale_x and scale_y.
Convert the "scaled zero centered" coordinates to "top left (0, 0)" by adding x_scaled_center and y_scaled_center.
Computing the center accurately:
The Python conversion is:
(0, 0) is the top left, and (cols-1, rows-1) is the bottom right coordinate.
The accurate center coordinate is:
x_original_center = (original_rows-1)/2
y_original_center = (original_cols-1)/2
Python code (assume img is the original image):
resized_img = cv2.resize(img, [int(cols*scale_x), int(rows*scale_y)])
rows, cols = img.shape[0:2]
resized_rows, resized_cols = resized_img.shape[0:2]
x_original_center = (cols-1) / 2
y_original_center = (rows-1) / 2
x_scaled_center = (resized_cols-1) / 2
y_scaled_center = (resized_rows-1) / 2
# Subtract the center, scale, and add the "scaled center".
x_scaled = (x_original - x_original_center)*scale_x + x_scaled_center
y_scaled = (y_original - y_original_center)*scale_y + y_scaled_center
Testing
The following code sample draws crosses at few original and scaled coordinates:
import cv2
def draw_cross(im, x, y, use_color=False):
""" Draw a cross with center (x,y) - cross is two rows and two columns """
x = int(round(x - 0.5))
y = int(round(y - 0.5))
if use_color:
im[y-4:y+6, x] = [0, 0, 255]
im[y-4:y+6, x+1] = [255, 0, 0]
im[y, x-4:x+6] = [0, 0, 255]
im[y+1, x-4:x+6] = [255, 0, 0]
else:
im[y-4:y+6, x] = 0
im[y-4:y+6, x+1] = 255
im[y, x-4:x+6] = 0
im[y+1, x-4:x+6] = 255
img = cv2.imread('graf.png') # http://man.hubwiz.com/docset/OpenCV.docset/Contents/Resources/Documents/db/d70/tutorial_akaze_matching.html
rows, cols = img.shape[0:2] # cols = 320, rows = 256
# 3 points for testing:
x0_original, y0_original = cols//2-0.5, rows//2-0.5 # 159.5, 127.5
x1_original, y1_original = cols//5-0.5, rows//4-0.5 # 63.5, 63.5
x2_original, y2_original = (cols//5)*3+20-0.5, (rows//4)*3+30-0.5 # 211.5, 221.5
draw_cross(img, x0_original, y0_original) # Center of cross (159.5, 127.5)
draw_cross(img, x1_original, y1_original)
draw_cross(img, x2_original, y2_original)
scale_x = 2.5
scale_y = 2
resized_img = cv2.resize(img, [int(cols*scale_x), int(rows*scale_y)], interpolation=cv2.INTER_NEAREST)
resized_rows, resized_cols = resized_img.shape[0:2] # cols = 800, rows = 512
# Compute center column and center row
x_original_center = (cols-1) / 2 # 159.5
y_original_center = (rows-1) / 2 # 127.5
# Compute center of resized image
x_scaled_center = (resized_cols-1) / 2 # 399.5
y_scaled_center = (resized_rows-1) / 2 # 255.5
# Compute the destination coordinates after resize
x0_scaled = (x0_original - x_original_center)*scale_x + x_scaled_center # 399.5
y0_scaled = (y0_original - y_original_center)*scale_y + y_scaled_center # 255.5
x1_scaled = (x1_original - x_original_center)*scale_x + x_scaled_center # 159.5
y1_scaled = (y1_original - y_original_center)*scale_y + y_scaled_center # 127.5
x2_scaled = (x2_original - x_original_center)*scale_x + x_scaled_center # 529.5
y2_scaled = (y2_original - y_original_center)*scale_y + y_scaled_center # 443.5
# Draw crosses on resized image
draw_cross(resized_img, x0_scaled, y0_scaled, True)
draw_cross(resized_img, x1_scaled, y1_scaled, True)
draw_cross(resized_img, x2_scaled, y2_scaled, True)
cv2.imshow('img', img)
cv2.imshow('resized_img', resized_img)
cv2.waitKey()
cv2.destroyAllWindows()
Original image:
Resized image:
Making sure the crosses are aligned:
Note:
In my answer I was using the naming conventions of Miki's comment.

Can't open "frozen_east_text_detection.pb" in function 'c

the full error says:
cv2.error: OpenCV(4.1.0) C:\projects\opencv-python\opencv\modules\dnn\src\caffe\caffe_io.cpp:1132: error: (-2:Unspecified error) FAILED: fs.is_open(). Can't open "frozen_east_text_detection.pb" in function 'c
here i have the code:
import time
from imutils.object_detection import non_max_suppression
import numpy as np
import cv2
import argparse
imagePath = "C:/xampp/htdocs/Tensorflow/TextDetection-master/images/tabla1.jpg"
east = "frozen_east_text_detection.pb"
newW = 640
newH = 480
min_confidence = 0.5
image = cv2.imread(imagePath) # it is working variable
orig = image.copy()
(H,W) = image.shape[:2]
set the new width an height and then determine the ratio in change
rW = W / float(newW)
rH = H / float(newH)
resize the image and grab the new image dimensions
image = cv2.resize(image, (newW, newH))
(H,W) = image.shape[:2]
"""
In order to perform text detection using OpenCV and the EAST deep learning model,
we need to extract the output feature maps of TWO LAYERS
"""
# Define the TWO output layer names ofr the EAST detector model
# FIRST LAYER : output probabilities of a region containing text or not.
# SECOND LAYER: bounding box coordinates of text.
layerNames = [
"feature_fusion/Conv_7/Sigmoid",
"feature_fusion/concat_3"
]
print("[INFO] loading EAST detector")
net = cv2.dnn.readNet( east ) #Load the Nerual Network into memory
# construct a blob from the image and then perform a forward pass of
# the model to obtain the two output layer sets
blob = cv2.dnn.blobFromImage( #https://www.pyimagesearch.com/2017/11/06/deep-learning-opencvs-blobfromimage-works/
image , 1.0 , (W,H) , (123.68, 116.78, 103.94) , swapRB=True, crop=False
)
start = time.time()
net.setInput(blob)
(scores, geometry) = net.forward(layerNames)
end = time.time()
print("[INFO] text detection took {:.6f} seconds".format(end-start))
# grab the umber of rows and columns from the scores volume, then
# initialize aour set of bounding box rectagles and corresponding
# cofidence scores
(numRows, numCols) = scores.shape[2:4]
rects = []
confidences = []
# loop over the number of rows
for y in range(0,numRows):
#extract the scores (probabilities), followed by the geometrical
#data used to derive potential bounding box coordinates that
#surround text
scoresData = scores[0, 0, y]
xData0 = geometry[0, 0, y]
xData1 = geometry[0, 1, y]
xData2 = geometry[0, 2, y]
xData3 = geometry[0, 3, y]
anglesData = geometry[0, 4, y]
#loop over the number of columns
for x in range(0, numCols):
#i our score does not have sufficient probability, ignore it
if (scoresData[x] < min_confidence):
continue
# compute the offset factor as our resulting feature maps will
# be 4x smaller than the input image
(offsetX, offsetY) = (x * 4.0 , y * 4.0)
# extract the rotation angle for the prediction and then
# compute the sin and cosine
angle = anglesData[x]
cos = np.cos(angle)
sin = np.sin(angle)
# use the geometry volume to derive the width and height of
# the bounding box
h = xData0[x] + xData2[x]
w = xData1[x] + xData3[x]
# compute both the starting and ending (x,y)-coordinates for
# the text prediction bounding box
endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x]) )
endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x]) )
startX = int(endX - w)
startY = int(endY - h)
#add the bounding box coordinates and probability score to
#our respective lists
rects.append( (startX, startY, endX, endY) )
confidences.append( scoresData[x] )
#apply non-maxima suppression to suppress weak, overlapping bounding boxes
boxes = non_max_suppression(np.array(rects) , probs=confidences) #imutils-> https://github.com/jrosebr1/imutils/blob/master/imutils/object_detection.py#L4
#loop over the bounding boxes
for (startX, startY, endX, endY) in boxes:
# scale the bounding box coordinates based on the respective ratios
startX = int(startX * rW)
startY = int(startY * rH)
endX = int(endX * rW)
endY = int(endY *rH)
#draw the bounding box on the image
cv2.rectangle( orig , (startX,startY) , (endX,endY) , (0,255,0) , 2 )
#show the outut image
cv2.imshow("Text detection",orig)
cv2.waitKey(0)
cv2.destroyAllWindows()
you can fix this by providing the absolute filepath of frozen_east_text_detection.pb from the main function of your code
Use this link to download model
https://www.dropbox.com/s/r2ingd0l3zt8hxs/frozen_east_text_detection.tar.gz?dl=1
you can further refer to OpenCV official blog
https://learnopencv.com/deep-learning-based-text-detection-using-opencv-c-python/

Can I randomly add a small image (13x12) to an array of pixels (random pixels of the same size of my small image)

I have 20 small images (that I want to put in a target area of a background image (13x12). I have already marked my target area with a circle, I have the coordinates of the circle in two arrays of pixels. Now I want to know how I can randomly add my 20 small images in random area in my arrays of pixels which are basically the target area (the drawn circle).
In my code, I was trying for just one image, if it works, I'll pass the folder of my 20 small images.
# Depencies importation
import cv2
import numpy as np
# Saving directory
saving_dir = "../Saved_Images/"
# Read the background image
bgimg = cv2.imread("../Images/background.jpg")
# Resizing the bacground image
bgimg_resized = cv2.resize(bgimg, (2050,2050))
# Read the image that will be put in the background image (exemple of 1)
# I'm just trying with one, if it works, I'll pass the folder of the 20
small_img = cv2.imread("../Images/small.jpg")
# Convert the resized background image to gray
bgimg_gray = cv2.cvtColor(bgimg, cv2.COLOR_BGR2GRAY)
# Convert the grayscale image to a binary image
ret, thresh = cv2.threshold(bgimg_gray,127,255,0)
# Determine the moments of the binary image
M = cv2.moments(thresh)
# calculate x,y coordinate of center
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# Drawing the circle in the background image
circle = cv2.circle(bgimg, (cX, cY), 930, (0,0,255), 9)
print(circle) # This returns None
# Getting the coordinates of the circle
combined = bgimg[:,:,0] + bgimg[:,:,1] + bgimg[:,:,2]
rows, cols = np.where(combined >= 0)
# I have those pixels in rows and cols, but I don't know
# How to randomly put my small image in those pixel
# Saving the new image
cv2.imwrite(saving_dir+"bgimg"+".jpg", bgimg)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.resizeWindow("Test", 1000, 1200)
# Showing the images
cv2.imshow("image", bgimg)
# Waiting for any key to stop the program execution
cv2.waitKey(0)
In the expected results, the small images must be placed in the background image randomly.
If you have the center and the radius of your circle, you can easily generate random coordinates by randomly choosing an angle theta from [0, 2*pi], calculating corresponding x and y values by cos(theta) and sin(theta) and scaling these by some random chosen scaling factors from [0, radius]. I prepared some code for you, see below.
I omitted a lot of code from yours (reading, preprocessing, saving) to focus on the relevant parts (see how to create a minimal, complete, and verifiable example). Hopefully, you can integrate the main idea of my solution into your code on your own. If not, I will provide further explanations.
import cv2
import numpy as np
# (Artificial) Background image (instead of reading an actual image...)
bgimg = 128 * np.ones((401, 401, 3), np.uint8)
# Circle parameters (obtained somehow...)
center = (200, 200)
radius = 100
# Draw circle in background image
cv2.circle(bgimg, center, radius, (0, 0, 255), 3)
# Shape of small image (known before-hand...?)
(w, h) = (13, 12)
for k in range(200):
# (Artificial) Small image (instead of reading an actual image...)
smallimg = np.uint8(np.add(128 * np.random.rand(w, h, 3), (127, 127, 127)))
# Select random angle theta from [0, 2*pi]
theta = 2 * np.pi * np.random.rand()
# Select random distance factors from center
factX = (radius - w/2) * np.random.rand()
factY = (radius - h/2) * np.random.rand()
# Calculate random coordinates for small image from angle and distance factors
(x, y) = np.uint16(np.add((np.cos(theta) * factX - w/2, np.sin(theta) * factY - h/2), center))
# Replace (rather than "add") determined area in background image with small image
bgimg[x:x+smallimg.shape[0], y:y+smallimg.shape[1]] = smallimg
cv2.imshow("bgimg", bgimg)
cv2.waitKey(0)
The exemplary output:
Caveat: I haven't paid attention, if the small images might violate the circle boundary. Therefore, some additional checks or limitations to the scaling factors must be added.
EDIT: I edited my above code. To take the below comment into account, I shift the small image by (width/2, height/2), and limit the radius scale factor accordingly, so that the circle boundary isn't violated, neither top/left nor bottom/right.
Before, it was possible, that the boundary is violated in the bottom/right part (n = 200):
After the edit, this should be prevented (n = 20000):
The touching of the red line in the image is due to the line's thickness. For "safety reasons", one could add another 1 pixel distance.

OpenCV Python rotate image by X degrees around specific point

I'm having a hard time finding examples for rotating an image around a specific point by a specific (often very small) angle in Python using OpenCV.
This is what I have so far, but it produces a very strange resulting image, but it is rotated somewhat:
def rotateImage( image, angle ):
if image != None:
dst_image = cv.CloneImage( image )
rotate_around = (0,0)
transl = cv.CreateMat(2, 3, cv.CV_32FC1 )
matrix = cv.GetRotationMatrix2D( rotate_around, angle, 1.0, transl )
cv.GetQuadrangleSubPix( image, dst_image, transl )
cv.GetRectSubPix( dst_image, image, rotate_around )
return dst_image
import numpy as np
import cv2
def rotate_image(image, angle):
image_center = tuple(np.array(image.shape[1::-1]) / 2)
rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR)
return result
Assuming you're using the cv2 version, that code finds the center of the image you want to rotate, calculates the transformation matrix and applies to the image.
Or much easier use
SciPy
from scipy import ndimage
#rotation angle in degree
rotated = ndimage.rotate(image_to_rotate, 45)
see
here
for more usage info.
def rotate(image, angle, center = None, scale = 1.0):
(h, w) = image.shape[:2]
if center is None:
center = (w / 2, h / 2)
# Perform the rotation
M = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(image, M, (w, h))
return rotated
I had issues with some of the above solutions, with getting the correct "bounding_box" or new size of the image. Therefore here is my version
def rotation(image, angleInDegrees):
h, w = image.shape[:2]
img_c = (w / 2, h / 2)
rot = cv2.getRotationMatrix2D(img_c, angleInDegrees, 1)
rad = math.radians(angleInDegrees)
sin = math.sin(rad)
cos = math.cos(rad)
b_w = int((h * abs(sin)) + (w * abs(cos)))
b_h = int((h * abs(cos)) + (w * abs(sin)))
rot[0, 2] += ((b_w / 2) - img_c[0])
rot[1, 2] += ((b_h / 2) - img_c[1])
outImg = cv2.warpAffine(image, rot, (b_w, b_h), flags=cv2.INTER_LINEAR)
return outImg
The cv2.warpAffine function takes the shape parameter in reverse order: (col,row) which the answers above do not mention. Here is what worked for me:
import numpy as np
def rotateImage(image, angle):
row,col = image.shape
center=tuple(np.array([row,col])/2)
rot_mat = cv2.getRotationMatrix2D(center,angle,1.0)
new_image = cv2.warpAffine(image, rot_mat, (col,row))
return new_image
import imutils
vs = VideoStream(src=0).start()
...
while (1):
frame = vs.read()
...
frame = imutils.rotate(frame, 45)
More: https://github.com/jrosebr1/imutils
You can simply use the imutils package to do the rotation. it has two methods
rotate: rotate the image at specified angle. however the drawback is image might get cropped if it is not a square image.
rotate_bound: it overcomes the problem happened with rotate. It adjusts the size of the image accordingly while rotating the image.
more info you can get on this blog:
https://www.pyimagesearch.com/2017/01/02/rotate-images-correctly-with-opencv-and-python/
Quick tweak to #alex-rodrigues answer... deals with shape including the number of channels.
import cv2
import numpy as np
def rotateImage(image, angle):
center=tuple(np.array(image.shape[0:2])/2)
rot_mat = cv2.getRotationMatrix2D(center,angle,1.0)
return cv2.warpAffine(image, rot_mat, image.shape[0:2],flags=cv2.INTER_LINEAR)
You need a homogenous matrix of size 2x3. First 2x2 is the rotation matrix and last column is a translation vector.
Here's how to build your transformation matrix:
# Exemple with img center point:
# angle = np.pi/6
# specific_point = np.array(img.shape[:2][::-1])/2
def rotate(img: np.ndarray, angle: float, specific_point: np.ndarray) -> np.ndarray:
warp_mat = np.zeros((2,3))
cos, sin = np.cos(angle), np.sin(angle)
warp_mat[:2,:2] = [[cos, -sin],[sin, cos]]
warp_mat[:2,2] = specific_point - np.matmul(warp_mat[:2,:2], specific_point)
return cv2.warpAffine(img, warp_mat, img.shape[:2][::-1])
You can easily rotate the images using opencv python-
def funcRotate(degree=0):
degree = cv2.getTrackbarPos('degree','Frame')
rotation_matrix = cv2.getRotationMatrix2D((width / 2, height / 2), degree, 1)
rotated_image = cv2.warpAffine(original, rotation_matrix, (width, height))
cv2.imshow('Rotate', rotated_image)
If you are thinking of creating a trackbar, then simply create a trackbar using cv2.createTrackbar() and the call the funcRotate()fucntion from your main script. Then you can easily rotate it to any degree you want. Full details about the implementation can be found here as well- Rotate images at any degree using Trackbars in opencv
Here's an example for rotating about an arbitrary point (x,y) using only openCV
def rotate_about_point(x, y, degree, image):
rot_mtx = cv.getRotationMatrix2D((x, y), angle, 1)
abs_cos = abs(rot_mtx[0, 0])
abs_sin = abs(rot_mtx[0, 1])
rot_wdt = int(frm_hgt * abs_sin + frm_wdt * abs_cos)
rot_hgt = int(frm_hgt * abs_cos + frm_wdt * abs_sin)
rot_mtx += np.asarray([[0, 0, -lftmost_x],
[0, 0, -topmost_y]])
rot_img = cv.warpAffine(image, rot_mtx, (rot_wdt, rot_hgt),
borderMode=cv.BORDER_CONSTANT)
return rot_img
you can use the following code:
import numpy as np
from PIL import Image
import math
def shear(angle,x,y):
tangent=math.tan(angle/2)
new_x=round(x-y*tangent)
new_y=y
#shear 2
new_y=round(new_x*math.sin(angle)+new_y)
#since there is no change in new_x according to the shear matrix
#shear 3
new_x=round(new_x-new_y*tangent)
#since there is no change in new_y according to the shear matrix
return new_y,new_x
image = np.array(Image.open("test.png"))
# Load the image
angle=-int(input("Enter the angle :- "))
# Ask the user to enter the angle of rotation
# Define the most occuring variables
angle=math.radians(angle)
#converting degrees to radians
cosine=math.cos(angle)
sine=math.sin(angle)
height=image.shape[0]
#define the height of the image
width=image.shape[1]
#define the width of the image
# Define the height and width of the new image that is to be formed
new_height = round(abs(image.shape[0]*cosine)+abs(image.shape[1]*sine))+1
new_width = round(abs(image.shape[1]*cosine)+abs(image.shape[0]*sine))+1
output=np.zeros((new_height,new_width,image.shape[2]))
image_copy=output.copy()
# Find the centre of the image about which we have to rotate the image
original_centre_height = round(((image.shape[0]+1)/2)-1)
#with respect to the original image
original_centre_width = round(((image.shape[1]+1)/2)-1)
#with respect to the original image
# Find the centre of the new image that will be obtained
new_centre_height= round(((new_height+1)/2)-1)
#with respect to the new image
new_centre_width= round(((new_width+1)/2)-1)
#with respect to the new image
for i in range(height):
for j in range(width):
#co-ordinates of pixel with respect to the centre of original image
y=image.shape[0]-1-i-original_centre_height
x=image.shape[1]-1-j-original_centre_width
#Applying shear Transformation
new_y,new_x=shear(angle,x,y)
new_y=new_centre_height-new_y
new_x=new_centre_width-new_x
output[new_y,new_x,:]=image[i,j,:]
pil_img=Image.fromarray((output).astype(np.uint8))
pil_img.save("rotated_image.png")

Categories

Resources