How to Change Pixel Coordinates? - python

I wrote my own affine transformation code, but I want to save the new pixel coordinates I created to apply to the image I own, how can I do this. So how can I save the new pixel coordinate of an image to this image? Here is an example of the part I couldn't do in this code.
img = cv2.imread("high1.jpeg", 0)
new_pixel_coor = np.dot(coefficient_pixel_mat, unknown_parameters).astype(int)
a = len(new_pixel_coor) // 2
new_pixel_coor = new_pixel_coor.reshape((a, 2))
print("Pixel Coordinates", "\n", new_pixel_coor)
img2 = np.zeros((width, height, 3), dtype=np.uint)
# There is an error. I could not do anything to save image
for w in range(width):
for h in range(height):
img[w][h] = img2[new_pixel_coor]
# Show and save the image
cv2.imshow('OutputImage.jpg', img2)
cv2.imwrite('OutputImage.jpg', img2)

Related

Rotate an image in python and fill the cropped area with image

Have a look at the image and it will give you the better idea what I want to achieve. I want to rotate the image and fill the black part of image just like in required image.
# Read the image
img = cv2.imread("input.png")
# Get the image size
h, w = img.shape[:2]
# Define the rotation matrix
M = cv2.getRotationMatrix2D((w/2, h/2), 30, 1)
# Rotate the image
rotated = cv2.warpAffine(img, M, (w, h))
mask = np.zeros(rotated.shape[:2], dtype=np.uint8)
mask[np.where((rotated == [0, 0, 0]).all(axis=2))] = 255
img_show(mask)
From the code I am able to get the mask of black regions. Now I want to replace these black regions with the image portion as shown in the image 1. Any better solution how can I achieve this.
Use the borderMode parameter of warpAffine.
You want to pass the BORDER_WRAP value.
Here's the result. This does exactly what you described with your first picture.
I have an approach. You can first create a larger image consisting of 3 * 3 times your original image. When you rotate this image and only cut out the center of this large image, you have your desired result.
import cv2
import numpy as np
# Read the image
img = cv2.imread("input.png")
# Get the image size of the origial image
h, w = img.shape[:2]
# make a large image containing 3 copies of the original image in each direction
large_img = np.tile(img, [3,3,1])
cv2.imshow("large_img", large_img)
# Define the rotation matrix. Rotate around the center of the large image
M = cv2.getRotationMatrix2D((w*3/2, h*3/2), 30, 1)
# Rotate the image
rotated = cv2.warpAffine(large_img, M, (w*3, h*3))
# crop only the center of the image
cropped_image = rotated[w:w*2,h:h*2,:]
cv2.imshow("cropped_image", cropped_image)
cv2.waitKey(0)

Save cropped image from bbox

I am using cvlib for detecting object and I want to be able to save the cropped imaged based on the bbox coordinates.
I have this in my code:
def detect_object(img):
# Open image
image_stream = io.BytesIO(img)
image_stream.seek(0)
file_bytes = np.asarray(bytearray(image_stream.read()), dtype=np.uint8)
frame = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
# Detection
bbox, label, conf = cv.detect_common_objects(frame)
output_image = draw_bbox(frame, bbox, label, conf)
return output_image, bbox, label, conf
and when I print bbox y get:
[3, -23, 1231, 731]
So, I want to use these coordinates to crop the original image and save only de detected object defined by these coordinates
Something like this:
crop = output_image[bbox[2]:bbox[1], bbox[0]:bbox[3],:]
cv2.imwrite("crop.png", crop)
But when I do this I realised that the crop doesn't contain the desired object, the coordinates are wrong.
How can I fix it? Why am I getting negative coordinates?
My Image is 1280x720 and the desired object occupies approximately the entire image.
I solved it using as reference the comment from #Christoph Rackwitz, i.e handling the offsets:
image_height, image_width, image_channels = output_image.shape
box_xmin, box_ymin, box_xmax, box_ymax = bbox
if box_xmin < 0:
box_xmin = 0
if box_ymin < 0:
box_ymin = 0
if box_xmax > image_width:
box_xmax = image_width
if box_ymax > image_height:
box_ymax = image_height
crop = output_image[box_ymin:box_ymax, box_xmin:box_xmax,:]
cv2.imwrite("crop.jpg", crop)

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)

Extract specific member of k-mean cluster of an image

I have an image (front facing man) with 4 different colors (background, hair, skin-tone, and cloth). I used k-mean with k=4, and image is segmented. Now what I want to do is extract out the hair out of the image.
I used canny edge detection to detect edge, which helped to detect the point in hair area(Pointed out by red dot). Now, I want to extract hair area, as the member of k-mean pointed out by the red dot. Is it possible?
Or is there any other way to extract out hair area from image of a person?
Code done till now is:
import cv2
import numpy as np
image1 = cv2.imread('Test1.jpg')
#Resizing Image for fixed width
def image_resize(image1, width = None, height = None, inter =
cv2.INTER_AREA):
# initialize the dimensions of the image to be resized and
# grab the image size
dim = None
(h, w) = image1.shape[:2]
# if both the width and height are None, then return the
# original image
if width is None and height is None:
return image1
# check to see if the width is None
if width is None:
# calculate the ratio of the height and construct the
# dimensions
r = height / float(h)
dim = (int(w * r), height)
# otherwise, the height is None
else:
# calculate the ratio of the width and construct the
# dimensions
r = width / float(w)
dim = (width, int(h * r))
# resize the image
resized = cv2.resize(image1, dim, interpolation = inter)
# return the resized image
return resized
img1 = image_resize(image1, width = 500)
cv2.imshow("Resized", img1)
cv2.waitKey(0)
#Detecting Edge of image
canny = cv2.Canny(img1, 100, 150)
cv2.imshow("Edge", canny)
cv2.waitKey(0)
coords = np.nonzero(canny)
topmost_y = np.min(coords[0])
#Blurring effect
img2 = cv2.medianBlur(img1, 5)
cv2.imshow("Blurred", img2)
cv2.waitKey(0)
#K-mean approach
Z = img2.reshape((-1,3))
Z = np.float32(Z)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K=4
ret, label1, center1 = cv2.kmeans(Z, K, None,
criteria, 10,
cv2.KMEANS_RANDOM_CENTERS)
center1 = np.uint8(center1)
res1 = center1[label1.flatten()]
output1 = res1.reshape((img2.shape))
cv2.circle(output1, (250, topmost_y + 20), 5, (0,0,255), -1)
cv2.imshow("k = 4", output1)
cv2.waitKey(0)
cv2.destroyAllWindows()
Images:
,
,
,
,
Given the code you already have you can get the xy coordinates of the cluster to which the hair belongs with just a few extra lines. You can also create an image that shows only the hair's cluster:
# find the index of the cluster of the hair
mask = label1.reshape(output1.shape[:-1])
khair = mask[(topmost_y + 20, 250)]
# get a mask that's True at all of the indices of hair's group
hairmask = mask==khair
# get the hair's cluster's xy coordinates
xyhair = hairmask.nonzero()
# plot an image with only the hair's cluster on a white background
cv2.imwrite("khair.jpg", np.where(hairmask[..., None], img1, [255,255,255]))
Here's what the hair's cluster looks like:
Once you have the hair's cluster, you can then find the blob that represents "just the hair". Here's how you'd do that:
import scipy.ndimage as snd
# label all connected blobs in hairmask
bloblab = snd.label(hairmask, structure=np.ones((3,3)))[0]
# create a mask for only the hair
haironlymask = bloblab == bloblab[topmost_y + 20, 250]
# get an image with just the hair and then crop it
justhair = np.where(haironlymask[..., None], img1, [255,255,255])
nz = haironlymask.nonzero()
justhair = justhair[nz[0].min():nz[0].max(), nz[1].min():nz[1].max()]
# save the image of just the hair on a white background
cv2.imwrite("justhair.jpg", justhair)
and here's the image of your hair by itself:
Now that you have one point in this hair region, propagate this point to all the other points.
The pseudo code would be:
set = red point
while set of hair doesn't change:
add all points (i-1, j) (i+1, j) (i, j-1) (i, j+1) to the set
intersect the set with the mask of brown points
At the end, you will have a mask with the hair.
You can do that easily in numpy by starting with a Boolean image with just one True element at the red dot and then use |= and &= operators. I suspect OpenCV also has this kind of morphological dilation operator.

only rotate part of image python

Can someone tell me how to rotate only part of an image like this:
How to find coordinate / center of this image:
i can rotate all pict using this
from PIL import Image
def rotate_image():
img = Image.open("nime1.png")
img.rotate(45).save("plus45.png")
img.rotate(-45).save("minus45.png")
img.rotate(90).save("90.png")
img.transpose(Image.ROTATE_90).save("90_trans.png")
img.rotate(180).save("180.png")
if __name__ == '__main__':
rotate_image()
You can crop an area of the picture as a new variable. In this case, I cropped a 120x120 pixel box out of the original image. It is rotated by 90 and then pasted back on the original.
from PIL import Image
img = Image.open('./image.jpg')
sub_image = img.crop(box=(200,0,320,120)).rotate(90)
img.paste(sub_image, box=(200,0))
So I thought about this a bit more and crafted a function that applies a circular mask to the cropped image before rotations. This allows an arbitrary angle without weird effects.
def circle_rotate(image, x, y, radius, degree):
img_arr = numpy.asarray(image)
box = (x-radius, y-radius, x+radius+1, y+radius+1)
crop = image.crop(box=box)
crop_arr = numpy.asarray(crop)
# build the cirle mask
mask = numpy.zeros((2*radius+1, 2*radius+1))
for i in range(crop_arr.shape[0]):
for j in range(crop_arr.shape[1]):
if (i-radius)**2 + (j-radius)**2 <= radius**2:
mask[i,j] = 1
# create the new circular image
sub_img_arr = numpy.empty(crop_arr.shape ,dtype='uint8')
sub_img_arr[:,:,:3] = crop_arr[:,:,:3]
sub_img_arr[:,:,3] = mask*255
sub_img = Image.fromarray(sub_img_arr, "RGBA").rotate(degree)
i2 = image.copy()
i2.paste(sub_img, box[:2], sub_img.convert('RGBA'))
return i2
i2 = circle_rotate(img, 260, 60, 60, 45)
i2
You can solve this problem as such. Say you have img = Image.open("nime1.png")
Create a copy of the image using img2 = img.copy()
Create a crop of img2 at the desired location using img2.crop(). You can read how to do this here
Paste img2 back onto img at the appropriate location using img.paste()
Notes:
To find the center coordinate, you can divide the width and height by 2 :)

Categories

Resources