How to Cut a Circular Part from an Image

How to cut a circular part from an image?

Here is another easier way to do with SVG:

body {

background:pink;

}
<svg width="200" height="200">

<defs>

<mask id="hole">

<circle r="100" cx="100" cy="100" fill="white"/>

<circle r="50" cx="180" cy="180" fill="black"/>

</mask>

<pattern id="img" patternUnits="userSpaceOnUse" width="200" height="200">

<image xlink:href="https://picsum.photos/200/200?image=1069" x="0" y="0" width="200" height="200" />

</pattern>

</defs>

<!-- create a rect, fill it with the image and apply the above mask -->

<rect fill="url(#img)" width="100%" height="100%" mask="url(#hole)" />

</svg>

What's the most simple way to crop a circle thumbnail from an image?

first: HoughCircles is used to detect circles on image, not to crop it.


You can't have circle image. Image is always rectangle but some of pixels can be transparent (alpha channel in RGBA) and programs will not display them.

So you can first crop image to have square and later add alpha channel with information which pixels should be visible. And here you can use mask with white circle on black background. At the end you have to save it as png or tiff because jpg can't keep alpha channel.


I use module PIL/pillow for this.

I crop square region in center of image but you can use different coordinates for this.

Next I create grayscale image with the same size and black background and draw white circle/ellipse.

Finally I add this image as alpha channel to cropped image and save it as png.

from PIL import Image, ImageDraw

filename = 'dog.jpg'

# load image
img = Image.open(filename)

# crop image
width, height = img.size
x = (width - height)//2
img_cropped = img.crop((x, 0, x+height, height))

# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', img_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = img_cropped.size
mask_draw.ellipse((0, 0, width, height), fill=255)
#mask.show()

# add mask as alpha channel
img_cropped.putalpha(mask)

# save as png which keeps alpha channel
img_cropped.save('dog_circle.png')

img_cropped.show()

Result

Sample Image


BTW:

In mask you can use values from 0 to 255 and different pixels may have different transparency - some of them can be half-transparent to make smooth border.

If you want to use it in HTML on own page then you don't have to create circle image because web browser can round corners of image and display it as circle. You have to use CSS for this.


EDIT: Example with more circles on mask.

Sample Image

from PIL import Image, ImageDraw

filename = 'dog.jpg'

# load image
img = Image.open(filename)

# crop image
width, height = img.size
x = (width - height)//2
img_cropped = img.crop((x, 0, x+height, height))

# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', img_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = img_cropped.size
mask_draw.ellipse((50, 50, width-50, height-50), fill=255)
mask_draw.ellipse((0, 0, 250, 250), fill=255)
mask_draw.ellipse((width-250, 0, width, 250), fill=255)

# add mask as alpha channel
img_cropped.putalpha(mask)

# save as png which keeps alpha channel
img_cropped.save('dog_2.png')

img_cropped.show()

cropping an image in a circular way, using python

Here's one way to do it:

#!/usr/local/bin/python3
import numpy as np
from PIL import Image, ImageDraw

# Open the input image as numpy array, convert to RGB
img=Image.open("dog.jpg").convert("RGB")
npImage=np.array(img)
h,w=img.size

# Create same size alpha layer with circle
alpha = Image.new('L', img.size,0)
draw = ImageDraw.Draw(alpha)
draw.pieslice([0,0,h,w],0,360,fill=255)

# Convert alpha Image to numpy array
npAlpha=np.array(alpha)

# Add alpha layer to RGB
npImage=np.dstack((npImage,npAlpha))

# Save with alpha
Image.fromarray(npImage).save('result.png')

Sample Image

CSS Circular Cropping of Rectangle Image

The approach is wrong, you need to apply the border-radius to the container div instead of the actual image.

This would work:

.image-cropper {
width: 100px;
height: 100px;
position: relative;
overflow: hidden;
border-radius: 50%;
}

img {
display: inline;
margin: 0 auto;
height: 100%;
width: auto;
}
<div class="image-cropper">
<img src="https://via.placeholder.com/150" class="rounded" />
</div>

cut out a specific part of an image with opencv in python

Here is one way in Python/OpenCV.

  • Read the image
  • Read the mask (separately created one time from your other image)
  • Convert the mask to gray and threshold it to binary, invert it and make it 3 channels
  • Get the center of the circle from your own code. (I have just measured it manually)
  • Set the expected x,y offsets of the bottom of the region of text from the center of the circle
  • Compute the expected top left corner of the mask from the center of the circle, the offsets and the height of the mask image
  • Put the mask into black image the size of the input at that location
  • Apply the new mask to the image to make the rest of the image black
  • Crop out the region of interest from the top left corner and the size of the original mask
  • OPTIONALLY, crop the original image
  • Save the results

Input image:

Sample Image

Prepared mask image:

Sample Image

import cv2
import numpy as np

# read image
img = cv2.imread('die.jpg')
ht, wd, cc = img.shape

# read mask as grayscale
mask = cv2.imread('die_mask.png', cv2.IMREAD_GRAYSCALE)

# threshold mask and invert
mask = cv2.threshold(mask,0,255,cv2.THRESH_BINARY)[1]
mask = 255 - mask
hh, ww = mask.shape

# make mask 3 channel
mask = cv2.merge([mask,mask,mask])

# set circle center
cx = 62
cy = 336

# offsets from circle center to bottom of region
dx = -20
dy = -27

# compute top left corner of mask using size of mask and center and offsets
left = cx + dx
top = cy + dy - hh

# put mask into black background image
mask2 = np.zeros_like(img)
mask2[top:top+hh, left:left+ww] = mask

# apply mask to image
img_masked = cv2.bitwise_and(img, mask2)

# crop region
img_masked_cropped = img_masked[top:top+hh, left:left+ww]

# ALTERNATE just crop input
img_cropped = img[top:top+hh, left:left+ww]

cv2.imshow('image', img)
cv2.imshow('mask', mask)
cv2.imshow('mask2', mask2)
cv2.imshow('masked image', img_masked)
cv2.imshow('masked cropped image', img_masked_cropped)
cv2.imshow('cropped image', img_cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save results
cv2.imwrite('die_mask_inserted.jpg', mask2)
cv2.imwrite('die_masked_image.jpg', img_masked)
cv2.imwrite('die_masked_cropped.jpg', img_masked_cropped)
cv2.imwrite('die_cropped.jpg', img_cropped)


Mask inserted in black image:

Sample Image

Masked image:

Sample Image

Crop of masked image:

Sample Image

(Optional) Crop of input image:

Sample Image

Cropping circle from image using opencv python

1. Create a mask:

height,width = img.shape
mask = np.zeros((height,width), np.uint8)

2. Draw the circles on that mask (set thickness to -1 to fill the circle):

circle_img = cv2.circle(mask,(i[0],i[1]),i[2],(255,255,255),thickness=-1)

3. Copy that image using that mask:

masked_data = cv2.bitwise_and(img1, img1, mask=circle_img)

4. Apply Threshold

_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)

5. Find Contour

contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])

6. Crop masked_data

crop = masked_data[y:y+h,x:x+w]

Adding this to your code

import cv2
import numpy as np

img1 = cv2.imread('amol.jpg')
img = cv2.imread('amol.jpg',0)
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY)

# Create mask
height,width = img.shape
mask = np.zeros((height,width), np.uint8)

edges = cv2.Canny(thresh, 100, 200)
#cv2.imshow('detected ',gray)
cimg=cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 10000, param1 = 50, param2 = 30, minRadius = 0, maxRadius = 0)
for i in circles[0,:]:
i[2]=i[2]+4
# Draw on mask
cv2.circle(mask,(i[0],i[1]),i[2],(255,255,255),thickness=-1)

# Copy that image using that mask
masked_data = cv2.bitwise_and(img1, img1, mask=mask)

# Apply Threshold
_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)

# Find Contour
contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])

# Crop masked_data
crop = masked_data[y:y+h,x:x+w]

#Code to close Window
cv2.imshow('detected Edge',img1)
cv2.imshow('Cropped Eye',crop)
cv2.waitKey(0)
cv2.destroyAllWindows()

Result using your image:

Sample Image

Most efficient way to crop image to circle (in R)?

You can improve the performance of your circ function if you do a vectorised subset-assign operation on your array (instead of looping) using the the fact that (x-xc)^2 +(y-yc)^2 > r^2 for points outside a circle.

To do this, replace the 2nd part of your function with

  # Second part of the function traces circle by...
x = rep(1:xmax, ymax)
y = rep(1:ymax, each=xmax)
r2 = r^2
ma[,,4][which(( (x-xc)^2 + (y-yc)^2 ) > r2)] <- 0
return(ma)


Related Topics



Leave a reply



Submit