How to display an image in polar coordinates with Python? - python

I'm looking for a way to transform an image in polar coordinates using Python. The result I expect is the same as the following image (done in Matlab): https://i.stack.imgur.com/CKBBd.png
I already tried using cv2.linearPolar but I couldn't achieve this result.

Something like this should work:
import cv2
image = cv2.imread('image.jpg')
h, w, _ = image.shape
image2 = cv2.linearPolar(image, (w / 2, h / 2), min(w, h) / 2,
cv2.WARP_INVERSE_MAP + cv2.WARP_FILL_OUTLIERS)

Related

how to get the pixels of an image upto a particular radius in python

I'm trying to get the pixels of a particular point up to a radius as the circle in the image below. I know this is possible with contours, but contours are too slow and I need to get those pixels in real-time
image: https://i.stack.imgur.com/GVe9H.png
thanks in advance
You can exploit the numpy meshgrid function together with some geometry:
h, w = # img size
y, x = # point location
xx, yy = np.meshgrid(np.linspace(0, h-1, h), np.linspace(0, w-1, w))
mask = (xx-x)**2 + (yy-y)**2 < radius**2
Then, to get the image pixels:
extracted_image = image * mask

Pinch/bulge distortion using Python OpenCV

I want to apply a pinch/bulge filter on an image using Python OpenCV. The result should be some kind of this example:
https://pixijs.io/pixi-filters/tools/screenshots/dist/bulge-pinch.gif
I've read the following stackoverflow post that should be the correct formula for the filter: Formulas for Barrel/Pincushion distortion
But I'm struggling to implement this in Python OpenCV.
I've read about maps to apply filter on an image: Distortion effect using OpenCv-python
As for my understanding, the code could look something like this:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# set up the x and y maps as float32
flex_x = np.zeros((h, w), np.float32)
flex_y = np.zeros((h, w), np.float32)
# create map with the barrel pincushion distortion formula
for y in range(h):
for x in range(w):
flex_x[y, x] = APPLY FORMULA TO X
flex_y[y, x] = APPLY FORMULA TO Y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
Is this the correct way to achieve the distortion presented in the example image? Any help regarding useful ressources or preferably examples are much appreciated.
After familiarizing myself with the ImageMagick source code, I've found a way to apply the formula for distortion. With the help of the OpenCV remap function, this is a way to distort an image:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# set up the x and y maps as float32
flex_x = np.zeros((h, w), np.float32)
flex_y = np.zeros((h, w), np.float32)
# create map with the barrel pincushion distortion formula
for y in range(h):
delta_y = scale_y * (y - center_y)
for x in range(w):
# determine if pixel is within an ellipse
delta_x = scale_x * (x - center_x)
distance = delta_x * delta_x + delta_y * delta_y
if distance >= (radius * radius):
flex_x[y, x] = x
flex_y[y, x] = y
else:
factor = 1.0
if distance > 0.0:
factor = math.pow(math.sin(math.pi * math.sqrt(distance) / radius / 2), -amount)
flex_x[y, x] = factor * delta_x / scale_x + center_x
flex_y[y, x] = factor * delta_y / scale_y + center_y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
This has the same effect as using the convert -implode function from ImageMagick.
You can do that using implode and explode options in Python Wand, which uses ImageMagick.
Input:
from wand.image import Image
import numpy as np
import cv2
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(0.5)
img.save(filename='zelda1_implode.jpg')
# convert to opencv/numpy array format
img_implode_opencv = np.array(img)
img_implode_opencv = cv2.cvtColor(img_implode_opencv, cv2.COLOR_RGB2BGR)
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(-0.5 )
img.save(filename='zelda1_explode.jpg')
# convert to opencv/numpy array format
img_explode_opencv = np.array(img)
img_explode_opencv = cv2.cvtColor(img_explode_opencv, cv2.COLOR_RGB2BGR)
# display result with opencv
cv2.imshow("IMPLODE", img_implode_opencv)
cv2.imshow("EXPLODE", img_explode_opencv)
cv2.waitKey(0)
Implode:
Explode:

Python3: Resize rectangular image to a different kind of rectangle, keeping ratio and fill background with black

I have a very similar question to this: Resize rectangular image to square, keeping ratio and fill background with black, but I would like to resize to a nonsquare image and center the image either horizontally or vertically if needed.
Here are some examples of desired outputs. I made this image entirely with Paint, so the images might not actually be perfectly centered, but centering is what I'd like to achieve:
I tried the following code that I edited from the question linked:
def fix_size(fn, desired_w=256, desired_h=256, fill_color=(0, 0, 0, 255)):
"""Edited from https://stackoverflow.com/questions/44231209/resize-rectangular-image-to-square-keeping-ratio-and-fill-background-with-black"""
im = Image.open(fn)
x, y = im.size
#size = max(min_size, x, y)
w = max(desired_w, x)
h = max(desired_h, y)
new_im = Image.new('RGBA', (w, h), fill_color)
new_im.paste(im, ((w - x) // 2, (h - y) // 2))
return new_im.resize((desired_w, desired_h))
That doesn't work however as it still stretches some images into square shaped ones (at least the image b in the example. What comes to big images, it seems to rotate them instead!
The problem lies in your incorrect calculation of the image size:
w = max(desired_w, x)
h = max(desired_h, y)
You're simply taking the maximum of dimension independently - without taking into account the aspect ratio of the image. Imagine if your input is a square 1000x1000 image. You would end up creating a black 1000x1000 image, pasting the original image over it, and then resizing it to 244x138. To get the correct result, you would have to create a 1768x1000 image instead of a 1000x1000 image.
Here's the updated code that takes the aspect ratio into account:
def fix_size(fn, desired_w=256, desired_h=256, fill_color=(0, 0, 0, 255)):
"""Edited from https://stackoverflow.com/questions/44231209/resize-rectangular-image-to-square-keeping-ratio-and-fill-background-with-black"""
im = Image.open(fn)
x, y = im.size
ratio = x / y
desired_ratio = desired_w / desired_h
w = max(desired_w, x)
h = int(w / desired_ratio)
if h < y:
h = y
w = int(h * desired_ratio)
new_im = Image.new('RGBA', (w, h), fill_color)
new_im.paste(im, ((w - x) // 2, (h - y) // 2))
return new_im.resize((desired_w, desired_h))

Python and OpenCV - How do we define region?

I came across the following code:
import cv2
image = cv2.imread('xyz.jpg')
(h, w) = image.shape[:2]
# compute the center of the image
(cX, cY) = (w / 2, h / 2)
region = image[0:cY, 0:cX]
How can we read this part image[0:cY, 0:cX]? I tried printing out the result, but got an array printed out that couldn't help me understand the idea.
So, for instance, let's say that the center of the image was (50,50), how would region be defined in this case?
Thanks.

Overlay images using python library

I wanted to overlay one image over another dynamically using a Python library, and was wondering which one would be easy to use.
Thanks for your help!
If you want to overlay two images, simply use the OpenCV libraries.
[Sample]
Here is the sample python code using OpenCV to overlay image1 and image2
import cv2
import numpy as np
def overlay(image1, image2, x, y):
image1_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
_, contours, _ = cv2.findContours(image1_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image1_mask = np.zeros_like(image1)
cv2.drawContours(image1_mask, contours, -1, (255,255,255), -1)
idx = np.where(image1_mask == 255)
image2[y+idx[0], x+idx[1], idx[2]] = image1[idx[0], idx[1], idx[2]]
return image2
if __name__ == '__main__':
grass_img = cv2.imread('grassland.jpg')
horse_img = cv2.imread('horse.png')
overlayed = overlay(horse_img, grass_img, 300, 300)
cv2.imwrite('overlayed.png', overlayed)
The result image was resized to reduce its volume, but in the above code, the resize code was omitted.
Result:
Update!
Here is the code using image's alpha value, and the output is better than before.
The idea is from overlay a smaller image on a larger image python OpenCv
def better_overlay(image1, image2, x, y):
image1_alpha = image1[:, :, 3] / 255.0
height, width = image1.shape[0], image1.shape[1]
for c in range(3):
image2[y:y+height, x:x+width, c] = image1_alpha * image1[:, :, c] + (1.0 - image1_alpha)* image2[y:y+height, x:x+width, c]
return image2
Result:
Usually PIL(Python Imaging Library) is for image processing stuff.

Categories