enter image description here
How to make this picture no longer sawtooth around? Without changing the color array.
Here is one way to do that by blurring a mask in Python/OpenCV.
Read the input
Convert to gray
Threshold to create a mask
Blur the mask and stretch so that 127.5 goes to 0 and 255 stays at 255
Convert the mask to float in range 0 to 1
Multiply the input by the mask and convert back to 8-bit integer and clip to range 0 to 255
Save the results
Input:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('man.jpg')
# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 16, 255, cv2.THRESH_BINARY)[1]
# blur threshold image
blur = cv2.GaussianBlur(thresh, (0,0), sigmaX=5, sigmaY=5, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
mask = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.float32) / 255
mask = cv2.merge([mask,mask,mask])
# replace alpha channel in input with new alpha channel
result = (mask * img).clip(0,255).astype(np.uint8)
# save output
cv2.imwrite('man_thresh.png', thresh)
cv2.imwrite('man_mask.png', mask)
cv2.imwrite('man_antialiased.png', result)
# Display various images to see the steps
cv2.imshow('gray',gray)
cv2.imshow('thresh', thresh)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold image:
Mask image:
Result:
Related
Hi I am trying to get a mask of a T-shirt.
Here is what I am getting:
However, I would like to only receive the garment's shape without the print in the middle. How can I do that?
Thanks!
Here is the code:
import cv2
import numpy as np
# load image whose you want to create mask
img = cv2.imread('01430_00.jpg')
# convert to graky
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image as mask
mask = cv2.threshold(gray,220,220, cv2.THRESH_BINARY)[1]
# negate mask
mask = 255 - mask
# apply morphology to remove isolated extraneous noise
# use borderconstant of black since foreground touches the edges
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# anti-alias the mask -- blur then stretch
# blur alpha channel
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=2, sigmaY=2, borderType =
cv2.BORDER_DEFAULT)
# linear stretch so that 127.5 goes to 0, but 255 stays 255
mask = (2*(mask.astype(np.float32))-255.0).clip(0,255).astype(np.uint8)
# Show Image in Opencv Windows
cv2.imshow("Original", img)
cv2.imshow("MASK", mask)
# Save mask Image
cv2.imwrite("Mask2.jpg",mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
You already have a large contour for "garment". You can fill inside of the largest contour with the following code
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(contours, key = cv2.contourArea)
cv2.drawContours(mask,[cnt],0,255,-1)
I'm currently working on a simple photo editor using CV2 in the backend and I'm wondering whether it is possible to add a bloom effect to the image using CV2.
Thanks for every help!
One can achieve a bloom effect in Python/OpenCV as follows:
- Read the input
- Convert to HSV colorspace as floats and separate channels
- Invert the saturation channel and multiply with the value channel, since to find white, we need low saturation and high brightness
- Blur the product and convert to 3 channels
- Blend the blurred image with the original applying gain to the blurred image
- Save the result
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('barn.jpg')
# set arguments
thresh_value = 245 # threshold to find white
blur_value = 50 # bloom smoothness
gain = 6 # bloom gain in intensity
# convert image to hsv colorspace as floats
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float64)
h, s, v = cv2.split(hsv)
# Desire low saturation and high brightness for white
# So invert saturation and multiply with brightness
sv = ((255-s) * v / 255).clip(0,255).astype(np.uint8)
# threshold
thresh = cv2.threshold(sv, thresh_value, 255, cv2.THRESH_BINARY)[1]
# blur and make 3 channels
blur = cv2.GaussianBlur(thresh, (0,0), sigmaX=blur_value, sigmaY=blur_value)
blur = cv2.cvtColor(blur, cv2.COLOR_GRAY2BGR)
# blend blur and image using gain on blur
result = cv2.addWeighted(img, 1, blur, gain, 0)
# save output image
cv2.imwrite('barn_bloom.jpg', result)
# display IN and OUT images
cv2.imshow('image', img)
cv2.imshow('sv', sv)
cv2.imshow('thresh', thresh)
cv2.imshow('blur', blur)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
I currently have the following image and the salience map below which reflects the attention areas of the first image:
Both of them are the same size. What I am trying to do is amplify the region of areas that are very white in the salient region. For example, the eyes, collar and hair would be a bit more highlighted. I have the following code which I have tried to split the image into h, s, v and then multiply through but the output is black and white. Any help is greatly appreciated:
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv_image)
dimensions = (384, 384)
saliencyMap = cv2.resize(saliencyMap, dimensions)
s1 = s * saliencyMap.astype(s.dtype)
hsv_image = cv2.merge([h, s1, v])
out = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR)
cv2.imshow('example', out)
cv2.waitKey()
Here is how to do that in Python/OpenCV. Add the two images (from your other post). Modify the mask to have values near a mean of mid-gray. Separate the image into H,S,V channels. Apply the mask to the Saturation channel doing hard light composition. Combine the new saturation with the old hue and value channels and convert back to BGR.
Input 1:
Input 2:
Mask:
import cv2
import numpy as np
# read image 1
img1 = cv2.imread('img1.png')
hh, ww = img1.shape[:2]
# read image 2 and resize to same size as img1
img2 = cv2.imread('img2.png')
img2 = cv2.resize(img2, (ww,hh))
# read saliency mask as grayscale and resize to same size as img1
mask = cv2.imread('mask.png')
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
mask = cv2.resize(mask, (ww,hh))
# add img1 and img2
img12 = cv2.add(img1, img2)
# get mean of mask and shift mean to mid-gray
# desirable for hard light compositing
# add bias as needed
mean = np.mean(mask)
bias = -32
shift = 128 - mean + bias
mask = cv2.add(mask, shift)
# threshold mask at mid gray and convert to 3 channels
# (needed to use as src < 0.5 "if" condition in hard light)
thresh = cv2.threshold(mask, 128, 255, cv2.THRESH_BINARY)[1]
# convert img12 to hsv
hsv = cv2.cvtColor(img12, cv2.COLOR_BGR2HSV)
# separate channels
hue,sat,val = cv2.split(hsv)
# do hard light composite of saturation and mask
# see CSS specs at https://www.w3.org/TR/compositing-1/#blendinghardlight
satf = sat.astype(np.uint8)/255
maskf = mask.astype(np.uint8)/255
threshf = thresh.astype(np.uint8)/255
threshf_inv = 1 - threshf
low = 2.0 * satf * maskf
high = 1 - 2.0 * (1-satf) * (1-maskf)
new_sat = ( 255 * (low * threshf_inv + high * threshf) ).clip(0, 255).astype(np.uint8)
# combine new_sat with old hue and val
result = cv2.merge([hue,new_sat,val])
# save results
cv2.imwrite('img12_sat_hardlight.png', result)
# show results
cv2.imshow('img12', img12)
cv2.imshow('mask', mask)
cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
I am really new to opencv. How can I remove the noise in the background without losing info?
I started with this: and Otsu thresholded it. I've tried erosion, dilation, bilateral filtering. My goal is to get a rectangle on the borders so I can perspective transform the thresholded picture, but it has trouble finding contours. Or maybe is there a different and better approach?
Here is one way to do that in Python/OpenCV.
Read the input
Blur it
Convert to HSV and extract the saturation channel
Threshold the saturation image
Clean it up with morphology close and open and save as a mask
Recreate your OTSU threshold image
Write black to OTSU image where mask is black (zero)
For comparison, write black to Input image where mask is black (zero)
Save results
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('circuit_board.jpg')
# blur
blur = cv2.GaussianBlur(img, (3,3), 0)
# convert to hsv and get saturation channel
sat = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)[:,:,1]
# threshold saturation channel
thresh = cv2.threshold(sat, 50, 255, cv2.THRESH_BINARY)[1]
# apply morphology close and open to make mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
mask = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel, iterations=1)
# do OTSU threshold to get circuit image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# write black to otsu image where mask is black
otsu_result = otsu.copy()
otsu_result[mask==0] = 0
# write black to input image where mask is black
img_result = img.copy()
img_result[mask==0] = 0
# write result to disk
cv2.imwrite("circuit_board_mask.png", mask)
cv2.imwrite("circuit_board_otsu.png", otsu)
cv2.imwrite("circuit_board_otsu_result.png", otsu_result)
cv2.imwrite("circuit_board_img_result.png", img_result)
# display it
cv2.imshow("IMAGE", img)
cv2.imshow("SAT", sat)
cv2.imshow("MASK", mask)
cv2.imshow("OTSU", otsu)
cv2.imshow("OTSU_RESULT", otsu_result)
cv2.imshow("IMAGE_RESULT", img_result)
cv2.waitKey(0)
Mask image:
OTSU threshold image:
OTSU Result:
Image Result:
I was reading on how to filter colors using OpenCV and came across the following snippet.
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_red = np.array([0,160,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(img,img, mask= mask)
What does each value in lower_red mean? Does it denote lower and upper limits of H,S,V sequentially? Should it be read as minimum value of H as 0 and maximum value of H as 255?
I want to filter red color.
You are well on your way. I've added some code that shows a solution to your problem - combining two HSV color ranges in one mask.
Result:
Code:
import numpy as np
import cv2
# load image
img = cv2.imread("HSV.JPG")
# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Create first mask
lower_red = np.array([0,150,50])
upper_red = np.array([5,255,255])
# Threshold the HSV image to get only green colors
mask = cv2.inRange(hsv, lower_red, upper_red)
# apply mask to original image
res = cv2.bitwise_and(img,img, mask= mask)
#show image
cv2.imshow("Mask1", res)
# Create second mask
lower_red2 = np.array([175,150,50])
upper_red2 = np.array([179,255,255])
# Threshold the HSV image to get only green colors
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
# apply mask to original image
res2 = cv2.bitwise_and(img,img, mask= mask2)
#show image
cv2.imshow("Mask2", res2)
#combine masks
final_mask = cv2.bitwise_or(mask, mask2)
# apply mask to original image
result = cv2.bitwise_and(img,img, mask= final_mask)
#show image
cv2.imshow("Result", result)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Note: in the result image I show the results if the separate masks were applied to the original image. Of course you really only need the masks, which are black and white.