I have an image which is as given below and I have created the mask for that image (the red dots are generated from the mask). The points in the mask should ideally cover the entire black dots on the image but as I just have one co-ordinate for each black patch, the resultant image looks as given below.
How do I identify the surrounding pixels (greys and lighter blacks) and mark them as well? Is there any way or method that I can look up and implement.
If I'm understanding you correctly, you want to convert all the surrounding gray and dark pixels to red. If so, here's an approach using OpenCV. The idea is to load the image, convert to grayscale, then Otsu's threshold to obtain a 1-channel binary image. This will give us a mask where we can use np.where to color pixels red where there are white pixels on the mask. Here's the results:
Binary mask
Result
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)[1]
# Color pixels red where there are white pixels on the mask
image[np.where(thresh==255)] = [0,0,255]
# Display
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
Related
I have the following image:
Initial Image
I am using the following code the rotate the image:
from skimage.transform import rotate
image = cv2.imread('122.png')
rotated = rotate(image,34,cval=1,resize = True)
Once I execute this code, I receive the following image:
Rotated Image
To eliminate the blur on the image, I use the following code to set a threshold. Anything that is not white is turned to black (so the gray spots turn black). The code for that is as follows:
ret, thresh_hold = cv2.threshold(rotated, 0, 100, cv2.THRESH_BINARY)
plt.imshow(thresh_hold)
Instead of getting a nice clear picture, I receive the following:
Choppy Image
Does anyone know what I can do to improve the image quality, or adjust the threshold to create a clearer image?
I attempted to adjust the threshold to different values, but this changed the image to all black or all white.
One way to approach that is to simply antialias the image in Python/OpenCV.
To do that one simply converts to grayscale. Then blurs the image, then applies a stretch of the image.
Adjust the blur sigma to change the antialiasing.
Input:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('122.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# blur threshold image
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=2, sigmaY=2, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
result = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)
# save output
cv2.imwrite('122_antialiased.png', result)
# Display various images to see the steps
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
I have this image.
I want to make all the colored headings to white and the text in it to black.
I try below to make the image full black and white.
img_grey = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
thresh = 170
img_binary = cv2.threshold(img_grey, thresh, 250, cv2.THRESH_BINARY)[1]
cv2.imwrite('bw_img.jpg',img_binary)
Now those headings are black and text within those is white. But i want to make text black and heading layout white. So, can anyone helps me with that?
You may convert the image to HSV, apply threshold to find colored regions, and copy the result of cv2.threshold with cv2.THRESH_BINARY_INV only to the colored regions.
Main stages of the suggested solution:
Convert from BGR to HSV color space, and get the saturation color channel.
all black and white are zero, and colored pixels are above zero.
Apply threshold to the saturation channel.
Find contours on the binarized saturation channel.
Draw the contours as white (255 values) on black background to form a mask.
Apply morphological closing for closing some black gaps.
Get only the area inside the mask from img_binary_inv (result of your code using cv2.THRESH_BINARY_INV).
Copy masked img_binary_inv to img_grey only in pixels that mask is white.
Complete code sample:
import numpy as np
import cv2
img_bgr = cv2.imread('img.jpg') # Read image as BGR
img_grey = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) # Convert from BGR to grayscale.
thresh = 170
img_binary_inv = cv2.threshold(img_grey, thresh, 255, cv2.THRESH_BINARY_INV)[1] # Apply threshold and invert black/white
# Convert from BGR to HSV color space.
hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
# Get the saturation color channel - all black and white are zero, and colored pixels are above zero.
s = hsv[:, :, 1]
thresh = 100
s_binary = cv2.threshold(s, thresh, 255, cv2.THRESH_BINARY)[1] # Apply threshold to the saturation channel.
# Find contours on s_binary
cnts = cv2.findContours(s_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # Use index [-2] to be compatible to OpenCV 3 and 4
# Draw the contours as white (255 values) on black background.
mask = np.zeros_like(s_binary)
cv2.drawContours(mask, cnts, -1, 255, -1)
# Apply morphological closing for closing some black gaps.
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((3, 3)))
# Get only the area inside the mask from img_binary_inv
masked_binary_inv = cv2.bitwise_or(img_binary_inv, img_binary_inv, mask=mask)
# Copy masked_binary_inv to img_grey only in pixels that mask is white.
cv2.copyTo(masked_binary_inv, mask, img_grey)
cv2.imwrite('img_grey.png', img_grey) # Save result (as PNG and not JPEG for better quality).
# Show images
cv2.imshow('img_bgr', img_bgr)
cv2.imshow('s_binary', s_binary)
cv2.imshow('mask', mask)
cv2.imshow('masked_binary_inv', masked_binary_inv)
cv2.imshow('img_grey', img_grey)
cv2.waitKey()
cv2.destroyAllWindows()
Result (img_grey):
The result doesn't look so good, due to the relatively low quality of the input image.
Intermediate results:
s_binary:
mask:
masked_binary_inv:
I want to remove a background from x-ray to extract actual area. So My original
image looks like left image and I want to crop to look like image.
A solution with Python and Open-CV is appreciated.
There are multiple files and so we don't know the height and width to. Crop in advance. So it needs to be computed.
Here is one way to do that in Python/OpenCV.
Read the input
Convert to gray
Threshold
Blacken the bottom two white rows
Find where all white pixels are in the image
Get the bounds of those pixels
Crop the image at the bounds
Save the results
Input:
import cv2
import numpy as np
# load image as grayscale
img = cv2.imread('xray_chest.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
hh, ww = thresh.shape
# make bottom 2 rows black where they are white the full width of the image
thresh[hh-3:hh, 0:ww] = 0
# get bounds of white pixels
white = np.where(thresh==255)
xmin, ymin, xmax, ymax = np.min(white[1]), np.min(white[0]), np.max(white[1]), np.max(white[0])
print(xmin,xmax,ymin,ymax)
# crop the image at the bounds adding back the two blackened rows at the bottom
crop = img[ymin:ymax+3, xmin:xmax]
# save resulting masked image
cv2.imwrite('xray_chest_thresh.jpg', thresh)
cv2.imwrite('xray_chest_crop.jpg', crop)
# display result
cv2.imshow("thresh", thresh)
cv2.imshow("crop", crop)
cv2.waitKey(0)
cv2.destroyAllWindows()
Thresholded image with bottom two rows blackened:
Cropped input:
An alternate method would be to get the external contour of the white region from the thresholded image. Get the bounds of the contour. Then crop to those bounds.
I am applying filter. By using OpenCv live webcam is open and it detect face and apply filter. But i want to crop the face in circle and removed the extra background and save the image.
for example:
to this
How can i implement in python?
The idea is to create a black mask then draw the desired region to crop out in white using cv2.circle(). From there we can use cv2.bitwise_and() with the original image and the mask. To crop the result, we can use cv2.boundingRect() on the mask to obtain the ROI then use Numpy slicing to extract the result. For this example I used the center point as (335, 245). You can adjust the circle radius to increase or decrease the size of the circle.
Code
import cv2
import numpy as np
# Create mask and draw circle onto mask
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
x,y = 335, 245
cv2.circle(mask, (x,y), 110, (255,255,255), -1)
# Bitwise-and for ROI
ROI = cv2.bitwise_and(image, mask)
# Crop mask and turn background white
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
x,y,w,h = cv2.boundingRect(mask)
result = ROI[y:y+h,x:x+w]
mask = mask[y:y+h,x:x+w]
result[mask==0] = (255,255,255)
cv2.imshow('result', result)
cv2.waitKey()
I am trying to get the outline of an album cover and edge detectors (Canny, Laplace) pick up too much noise. I don't fully understand how image masking works and would like put a white mask over the image so I see only the black pixels
I have applied a GaussianBlur 5x5 and converted the image to hsv values. I have a range of values which are black, and I have filtered these out.
# imported image and processing (shorthand here)
image = cv2.imread(args["image"])
blur = cv2.GaussianBlur(image, (5,5), 0)
blur_hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
# set regions of color
boundaries = [
# black
([0,0,0],[180, 255, 40])
#pink
#([151, 80, 50], [174, 255, 255])
]
# loop over the boundaries
for (lower, upper) in boundaries:
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype = "uint8")
upper = np.array(upper, dtype = "uint8")
# find the colors within the specified boundaries and apply
mask = cv2.inRange(blur_hsv, lower, upper)
output = cv2.bitwise_and(image, image, mask = mask)
# show the images
cv2.imshow("images", np.hstack([image, output]))
I was hoping for some distinction in the final output, but the window is just black. How can I create a different color mask?
Edit:
Not the exact image, but a sample LEFT: original; RIGHT: processed
From my understanding, you want to obtain a mask where all colored pixels (non-black) are white. When we use cv2.inRange(), we give it a lower/upper threshold that returns all pixels within the bounds in white. Then when we use cv2.bitwise_and() with the mask and the original image, the resulting image will be the areas where both the mask and original image are white. Essentially any pixels in white are the areas that we want to keep.
Your current output shows all areas in the original picture that have pixels between the lower/upper threshold. But if your goal is to display all non-black pixels, then you can simply invert the mask. Here's a visualization:
Here's your current mask and represents all pixels within the thresholds in the original image as white.
We can simply invert the mask or use cv2.bitwise_not() to get your desired mask. This new mask represents all colored pixels not within your lower/upper threshold as white. Therefore this mask is all the colored pixels.
final_mask = 255 - mask
Remember, any pixels that we want to keep, we should make it white whereas any pixels we want to throw away, we make it black. So if we cv2.bitwise_and() this new mask with the original image, we get this
Here's a good tutorial on bitwise operations and masking
import cv2
import numpy as np
image = cv2.imread('1.png')
blur = cv2.GaussianBlur(image, (5,5), 0)
blur_hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
# create NumPy arrays from the boundaries
lower = np.array([0,0,0], dtype = "uint8")
upper = np.array([180,255,40], dtype = "uint8")
# find the colors within the specified boundaries and apply
mask = cv2.inRange(blur_hsv, lower, upper)
mask = 255 - mask
output = cv2.bitwise_and(image, image, mask = mask)
# show the images
cv2.imshow("output", output)
cv2.imshow("mask", mask)
cv2.waitKey()