Reputation: 731
I need to the stretch the images in X and Y directions but at the same time keep the target image size 300x300. I am using Open CV. Everytime I scale the image and then resize it, I lose the scaling and it looks the same as the image I fed it to scale. How do I accomplish this?
This is the code for scaling
def scale(infile,outfile,scx,scy):
img = cv2.imread(infile,0)
height, width = img.shape[:2]
#aspectRatio = width / height
rows,cols = img.shape
if scx > 1 or scy > 1:
scimg = cv2.resize(img,None, fx = scx, fy = scy, interpolation = cv2.INTER_LINEAR)
else:
scimg = cv2.resize(img,None, fx = scx, fy = scy, interpolation = cv2.INTER_CUBIC)
#cheight, cwidth = scimg.shape[:2]
#area = cheight * cwidth
#nheight = math.sqrt(area / aspectRatio)
#nwidth = nheight * aspectRatio
#cv2.resize(scimg,((int)(nwidth), (int)(nheight)), interpolation = cv2.INTER_CUBIC)
#top = (int) (0.2*rows)
#bottom = (int) (0.2*rows)
#left = (int) (0.2*cols)
#right = (int) (0.2*cols);
#cv2.copyMakeBorder(scimg,top,left,bottom,right,cv2.BORDER_CONSTANT,value=255)
cv2.imwrite(outfile,scimg)
and I use the scales array for x and y scale factors : scales = [(1,2),(2,1)]
I want that the final image should be 300x300 and should contain the scaled version of the image.
Thank you!!
Upvotes: 0
Views: 4983
Reputation: 23012
If you want this just for display purposes, the easiest way is to use cv2.imshow()
on your cropped image and use cv2.resizeWindow()
to set the window size to the original image size.
import cv2
import numpy as np
img = cv2.imread('lena.png')
h, w = img.shape[:2]
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image
cv2.namedWindow("Scaled image", cv2.WINDOW_NORMAL) # create a resizeable window
cv2.imshow("Scaled image", scaled_img) # display the image in the window
cv2.resizeWindow("Scaled image", w, h) # resize the window
cv2.waitKey(0)
Will display a scaled image inside the window where the window has the original image size. This will work even if you scale the image larger, by cropping the right side and top side of the image off (the image is anchored at the bottom left corner of the window). See the output window:
If, however, you want this to be saved into another matrix, then you'll need to pad the image with whatever color you want outside of the image. The easiest way is to create a matrix with that color, but then create an ROI the size of your scaled image and place the scaled image within the ROI.
import cv2
import numpy as np
img = cv2.imread('lena.png')
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image
sh, sw = scaled_img.shape[:2] # get h, w of scaled image
padded_scaled = np.zeros(img.shape, dtype=np.uint8)
padded_scaled[0:sh, 0:sw] = scaled_img
cv2.imshow("Scaled image", padded_scaled)
cv2.waitKey(0)
This will put the scaled image at 0,0
in the destination padded_scaled
:
If instead you want it displayed at the center, you can do some simple computations to get the center of the image, and then shift by half the width and height of the scaled image for the starting position.
import cv2
import numpy as np
img = cv2.imread('lena.png')
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image
h, w = img.shape[:2] # get h, w of image
sh, sw = scaled_img.shape[:2] # get h, w of scaled image
center_y = int(h/2 - sh/2)
center_x = int(w/2 - sw/2)
padded_scaled = np.zeros(img.shape, dtype=np.uint8) # using img.shape to obtain #channels
padded_scaled[center_y:center_y+sh, center_x:center_x+sw] = scaled_img
cv2.imshow("Scaled image", padded_scaled)
cv2.waitKey(0)
This will place the scaled image in the center of the padded matrix:
This will only work when images are scaled smaller than the original image, as you're placing a smaller image into a larger blank matrix. However, if you want to allow for larger scaling, then you'll need a crop at that point. You can just crop a region from the scaled image that is the same size as the original image. However, if the scale is larger than 1 in one dimension and less than 1 in another, you'll need to both crop and pad. I separated this into two sections of if
statements: first create a result that is at most the size of the image by cropping if necessary, and then pad if it's smaller.
import cv2
import numpy as np
img = cv2.imread('lena.png')
scale_x, scale_y = 13, .3 # define your scale
h, w = img.shape[:2] # get h, w of image
if scale_x > 1 or scale_y > 1:
scaled_img = cv2.resize(img, None, fx=scale_x, fy=scale_y, interpolation = cv2.INTER_LINEAR) # scale image
sh, sw = scaled_img.shape[:2] # get h, w of scaled image
center_y = int(sh/2 - h/2)
center_x = int(sw/2 - w/2)
cropped = scaled_img[center_y:center_y+h, center_x:center_x+w]
result = cropped
elif scale_x > 0 or scale_y > 0:
scaled_img = cv2.resize(img, None, fx=scale_x, fy=scale_y, interpolation = cv2.INTER_CUBIC) # scale image
result = scaled_img
else: # scale_x or scale_y is negative
print("Scales must be greater than 0; returning the original image.")
result = img
if result.shape < img.shape: # one of the dimensions was scaled smaller, so need to pad
sh, sw = result.shape[:2] # get h, w of cropped, scaled image
center_y = int(h/2 - sh/2)
center_x = int(w/2 - sw/2)
padded_scaled = np.zeros(img.shape, dtype=np.uint8)
padded_scaled[center_y:center_y+sh, center_x:center_x+sw] = result
result = padded_scaled
cv2.imshow("Scaled padded/cropped image", result)
cv2.waitKey(0)
With a large stretch in one direction and a smaller scale in the other, this will result in an image displayed like this:
Upvotes: 1