Navdeep
Navdeep

Reputation: 863

Resizing ROI in an image

I have a 565 * 584 image as shownenter image description here

I want to reduce the radius of the circle by certain number of pixels without changing the size of the image. How can I do it? Please explain or give some ideas. Thank You.

Upvotes: 1

Views: 1846

Answers (3)

rayryeng
rayryeng

Reputation: 104504

Here's how you'd do it in OpenCV Python. Going with Mark Setchell's approach, simply specify a round structuring element so that you can maintain or respect the round edges of the object. The closest thing that OpenCV has to offer is the elliptical mask.

As such:

import numpy as np # Import relevant packages - numpy and OpenCV
import cv2

# Read in image and threshold - convert to grayscale first
im = cv2.imread('c8lfe.jpg', 0) > 128

# Specify radius of ellipse
radius = 21

# Obtain structuring element, then erode image
se = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (radius, radius))

# Make sure you convert back to grayscale and multiply by 255
out = 255*(cv2.erode(im, se).astype('uint8'))

# Show the image, wait for user key, then close window and write image
cv2.imshow('Reduced shape', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('out.png', out)

We get:

enter image description here

Be advised that the small bump at the top right corner of your shape will mutate. As we are essentially shrinking the perimeter of the object, that bump will also shrink as well. If you wish to preserve the structure of the object while maintaining the image resolution, use Mark Ransom's approach or my slightly modified version of his approach. Both are shown below.


However, to be self-contained, we can certainly do what Mark Ransom has suggested. Resize the image, initialize a blank image that is size of the original image, and place it in the centre:

import numpy as np # Import relevant packages - OpenCV and Python
import cv2

im = cv2.imread('c8lfe.jpg', 0) # Read in the image - grayscale
scale_factor = 0.75 # Set scale factor - We are shrinking the image by 25%

# Get the desired size (row and columns) of the shrunken image
desired_size = np.floor(scale_factor*np.array(im.shape)).astype('int')

# Make sure desired size is ODD for easier placement
if desired_size[0] % 2 == 0:
    desired_size[0] += 1
if desired_size[1] % 2 == 0:
    desired_size[1] += 1

# Resize the image.  Columns come first, followed by rows, which is why we 
# reverse the desired_size array
rsz = cv2.resize(im, tuple(desired_size[::-1]))

# Determine half width of both dimensions of shrunken image
half_way = np.floor(desired_size/2.0).astype('int')

# Create output image that is the same size as the input and find its centre
out = np.zeros_like(im, dtype='uint8')
centre = np.floor(np.array(im.shape)/2.0).astype('int')

# Place shrunken image in the centre of the larger output image
out[centre[0]-half_way[0]:centre[0]+half_way[0]+1, centre[1]-half_way[1]:centre[1]+half_way[1]+1] = rsz

# Show the image, wait for user key, then close window and write image
cv2.imshow('Reduced shape', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('out.png', out)

We get:

enter image description here


Another suggestion

What I can also recommend you do is pad the array with zeroes, then reshrink the image back to its original size. You would essentially extend the borders of the original image so that the borders contain zeroes. In this case, we would do what Mark Ransom also suggested, but we are working within the inside, out.

Here's the way to pad a matrix with zeroes using OpenCV C++: Pad array with zeros- openCV . However, in Python, simply use numpy's pad function:

import numpy as np # Import relevant packages - numpy and OpenCV
import cv2

# Read in image and threshold - convert to grayscale first
im = cv2.imread('c8lfe.jpg', 0)

# Set how many pixels along the border you want to add on each side
pad_radius = 75

# Pad the image
out = np.lib.pad(im, ((pad_radius, pad_radius), (pad_radius, pad_radius)), 'constant', constant_values=((0,0),(0,0)))

# Shrink it back to what the original size was
out = cv2.resize(out, im.shape[::-1])

# Show the image, wait for user key, then close window and write image
cv2.imshow('Reduced shape', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('out.png', out)

We thus get:

enter image description here

Upvotes: 3

Mark Ransom
Mark Ransom

Reputation: 308206

If you know that the background of the image is a constant, as in your example, this is easy.

Resize the entire image by the ratio you wish to shrink by. Then create a new image at the size of the original and fill it with the background color, then paste the resized image into the center of it.

enter image description here

Upvotes: 3

Mark Setchell
Mark Setchell

Reputation: 207465

I would use ImageMagick and an erosion like this:

convert https://i.sstatic.net/c8lfe.jpg -morphology erode octagon:8 out.png

enter image description here

Upvotes: 3

Related Questions