How to map pixels to values in a new image with python? - python

I'm trying to map an image to a velocity model, where the colors represent the velocities, so I read an image using OpenCV, take its dimensions, create an array of velocities within a certain range and try to recreate the image with these values, I saw an algoirthm very similar in matlab that works:
` vi=1000;
vf=4200;
M=imread('modelo_vr_2500x300.png');
Lx=size(M,1);
Ly=size(M,2);
N=M(1:Lx,1:Ly,1);
cor2=0:255;
vel2=cor2/256*(vf-vi)+vi;
V=zeros(size(N));
for i=1:length(cor2)
V=V+vel2(i)*(N==cor2(i));
end
imagesc(V)
colorbar`
So I tried to adapt it to Python, but it doesn't seem to work, all that I get is an image totally black, but if I print V, the new image, it has values, but they are quite high. I have no idea what I'm doing wrong, could anyone help?
import CV2
# read image
img = cv2.imread("figures/teste03-06B.png", cv2.IMREAD_UNCHANGED)
# get dimensions of image
dimensions = img.shape
# height = Ly, width = Lx, number of channels in image = Ch
Ly = img.shape[0]
Lx = img.shape[1]
Ch = img.shape[2]
N=img[0:Ly, 0:Lx, 0:Ch]
print('Image Dimension : ',dimensions)
print('Image Height : ',Ly)
print('Image Width : ',Lx)
print('Number of Channels : ',Ch)
cv2.imshow("Display window", img)
cv2.waitKey(0)
cv2.destroyWindow("Display window")
import numpy as np
vi=2000
vf=6000
color=np.array(range(256))
vel=((color/256)*(vf-vi))+vi
V = np.zeros_like(img)
for i in range(0,len(color)):
if N[i]==color[i]:
V=V+vel[i]
else:
V=V
print(V)
cv2.imshow("Display window", V)
cv2.waitKey(0)
cv2.destroyWindow("Display window")`
It doesn't give any error message, just doesn't work as it should, I have no idea why...

I think you're looking for this:
new_image = vel[img]
But you probably want to normalize vel first. Some variant of:
vel = vel/max(vel) * 255
vel = vel.astype(dtype=np.uint8)
I think that should work.

Related

Scaling an image makes no discernable change

I am using two different ways to re-size an image, but all three look exactly the same...
What am I doing wrong that no scaling occurs?
import cv2 as cv
import numpy as np
path = "resources/Shapes.png"
img = cv.imread(path)
cv.imshow("img", img)
res1 = cv.resize(img, None, fx = 2, fy = 2, interpolation = cv.INTER_CUBIC)
cv.imshow("res1", res1)
height, width = img.shape[:2]
res2 = cv.resize(img, (2 * width, 2 * height), interpolation = cv.INTER_CUBIC)
cv.imshow("res2", res2)
k = cv.waitKey(0)
Just putting this here for future reference:
The code above works, the issue was that imshow does not always show the true size of the image, by saving the different images, or simply examining them with res1.shape vs img.shape, you can see the true size of the image.

How to make a shape larger or smaller without changing the resolution of the image using OpenCV or PIL in Python

I would like to be able to make a certain shape in either a PIL image or an OpenCV image 3 times larger and smaller without changing the resolution of the image or changing the shape of the shape I want to make larger. I have tried using OpenCV's dilation method but that is not it's intended use, plus it changed the shape of the image. For an example:
Thanks.
Here's a way of doing it:
find the interesting shape, i.e. non-white ROI area
extract it
scale it up by a factor
clear the original image to white
paste the scaled ROI back into image with same centre
#!/usr/bin/env python3
import cv2
import numpy as np
if __name__ == "__main__":
# Open image
orig = cv2.imread('image.png',cv2.IMREAD_COLOR)
# Get extent of interesting part, i.e. non-white part
y, x, _ = np.nonzero(~orig)
y0, y1 = np.min(y), np.max(y) # top and bottom rows
x0, x1 = np.min(x), np.max(x) # left and right cols
h, w = y1-y0, x1-x0 # height and width
ROI = orig[y0:y1, x0:x1] # extract ROI
cv2.imwrite('ROI.png', ROI) # DEBUG only
# Upscale ROI
factor = 3
scaledROI = cv2.resize(ROI, (w*factor,h*factor), interpolation=cv2.INTER_NEAREST)
newH, newW = scaledROI.shape[:2]
# Clear original image to white
orig[:] = [255,255,255]
# Get centre of original shape, and position of top-left of ROI in output image
cx, cy = (x0 + x1) //2, (y0 + y1)//2
top = cy - newH//2
left = cx - newW//2
# Paste in rescaled ROI
orig[top:top+newH, left:left+newW] = scaledROI
cv2.imwrite('result.png', orig)
That transforms this:
to this:
Puts me in mind of a pantograph:

How to select ROI in video input in OpenCV (Python)?

I'm working on sign language recognition (hand gestures) using OpenCV. I want to select a particular region (ROI) as input from the entire frame and give it to the model. Right now, I'm able to do the same with the entire frame but can't have ROI. This is the code I've tried so far :
_, image_frame = cam_capture.read()
r = cv2.rectangle(image_frame, upper_left, bottom_right, (100, 50, 200), 5)
rect_img = image_frame[upper_left[1] : bottom_right[1], upper_left[0] : bottom_right[0]]
sketcher_rect = rect_img
sketcher_rect = sketch_transform(sketcher_rect)
cv2.resize(sketcher_rect, (28,28), interpolation = cv2.INTER_AREA)
pred_probab, pred_class = keras_predict(model, sketcher_rect)
print(pred_class, pred_probab)
cv2.imshow('image_frame',sketcher_rect)
Any help ?
If I understand you correctly you simply want to cut a region from the image right?
This should work:
def crop_image(image, x, y, width, height):
"""
image: a cv2 frame
x, y, width, height: the region to cut out
"""
return image[y:y + height, x:x + width]
Remember that cv2 images are simply numpy arrays. Cutting a region of the image is the same as extracting the indexes from the array.

Axis out of bounds error in Python using PIL and OpenCV 2

I wanted to change all the pixels in an image to a grey color (r = g = b = 128) if they are in a certain threshold (if the value is between 50 and 150 change it). I imported the image and when i try to process the image it gives me the following error : IndexError: index 3474 is out of bounds for axis 0 with size 3474 (the image is 3474x4632).
Here's the code:
from PIL import Image
import numpy as np
image = Image.open("texture.jpg")
w, h = image.size
print ("%d %d" % (w, h)) #to be sure what the width and height are
im = np.array(image)
for x in range(0, w):
for y in range(0, h):
if (im[x][y][0] <= 150 and im[x][y][0] >= 50):
im[x][y][0] = 128
im[x][y][1] = 128
im[x][y][2] = 128
cv2.imwrite("image2.jpg", im)
And here's the image i'm trying to convert: https://ibb.co/hnjq4p (too large to upload here). Any ideas about why it doesn't work ?
I believe that numpy reverses the axis order from PIL. Actually the first index is rows. So you should loop through w,h = im.shape or h,w = image.size instead. Maybe you can verify that this is correct by comparing image.size and im.shape?
That said, it will be much better if you do not loop. You can use masking and broadcasting to achieve the for loop task like this:
im[(im[...,0]<=150)&(im[...,0]>=50)] = 128 # will modify im in place
This will be much faster especially on large images like this.
Note that this only checks the first channel of the image to be between 150 and 50. This is what your for loop says so I guess it's what you want.
Please check im.shape: you should index your pixels as im[y,x] after converting to a numpy.array.

PIL: enlarge an image

I'm having trouble getting PIL to enlarge an image. Large images get scaled down just fine, but small images won't get bigger.
# get the ratio of the change in height of this image using the
# by dividing the height of the first image
s = h / float(image.size[1])
# calculate the change in dimension of the new image
new_size = tuple([int(x*s) for x in image.size])
# if this image height is larger than the image we are sizing to
if image.size[1] > h:
# make a thumbnail of the image using the new image size
image.thumbnail(new_size)
by = "thumbnailed"
# add the image to the images list
new_images.append(image)
else:
# otherwise try to blow up the image - doesn't work
new_image = image.resize(new_size)
new_images.append(new_image)
by = "resized"
logging.debug("image %s from: %s to %s" % (by, str(image.size), str(new_size)))
Both resize and transform methods properly resize images.
size_tuple = im.size
x1 = y1 = 0
x2, y2 = size_tuple
# resize
im = im.resize(size_tuple)
# transform
im = im.transform(size_tuple, Image.EXTENT, (x1,y1,x2,y2))
If you are having the same problem I described - try it on another machine. There must be something wrong with the python installation on my server. It worked fine on my local machine.
Here is a working example how to resize an image in every direction with openCV and numpy:
import cv2, numpy
original_image = cv2.imread('original_image.jpg',0)
original_height, original_width = original_image.shape[:2]
factor = 2
resized_image = cv2.resize(original_image, (int(original_height*factor), int(original_width*factor)), interpolation=cv2.INTER_CUBIC )
cv2.imwrite('resized_image.jpg',resized_image)
#fixed var name
Simple as that. You wanna use "cv2.INTER_CUBIC" to enlarge (factor > 1) and "cv2.INTER_AREA" to make the images smaller (factor < 1).

Categories