How to add colored line on rgba (.png) image using opencv?
I tried following but line drawn is transparent.
import cv2
image = cv2.imread("/content/drive/My Drive/universe-fg.png",-1)
from google.colab.patches import cv2_imshow
image2 = cv2.resize(image,(150,150))
cv2.line(image2, (20, 30), (100, 80), (255, 255, 0), 10)
cv2_imshow(image2)
The result:
using cv2 version 4.1.2
Your mistake is that you need to specify an opaque alpha value in your line color. So use (255, 255, 0, 255) rather than (255, 255, 0). The latter assumes a value of 0 (transparent) when not specified.
So here is how to do that in Python/OpenCV.
Input:
import cv2
import numpy as np
# load transparent image
img = cv2.imread('blue_circle.png', cv2.IMREAD_UNCHANGED)
hh, ww = img.shape[:2]
# draw colored line as opaque
result = img.copy()
cv2.line(result, (20, 30), (100, 80), (255, 255, 0, 255), 10)
# save result
cv2.imwrite('blue_circle_line.png', result)
# display result, though it won't show transparency
cv2.imshow("IMAGE", img)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Related
Facing problem while removing checkerboard pattern. I'm using cv2.Threshold but it selected unexpected pixels too (red marked) .
import cv2
import numpy as np
input = cv2.imread('image.png')
ret, logo_mask = cv2.threshold(input[:,:,0], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
cv2.imshow(logo_mask)
Input image:
Output image:
Anyone can help?
Getting perfect results that covers all cases is challenging.
The following solution assumes that the white checkerboard color is (255, 255, 255), and gray is (230, 230, 230).
Another assumptions is that the clusters with that specific colors in the other parts of the image are very small.
We may use the following stages:
Find "white mask" and "gray mask" where color is (255, 255, 255) and (230, 230, 230).
Create unified mask using bitwise or.
Find contours, and remove small contours from the mask (assumed to be "noise").
Code sample:
import cv2
import numpy as np
input = cv2.imread('image.png')
white_mask = np.all(input == 255, 2).astype(np.uint8)*255 # cv2.inRange(input, (255, 255, 255), (255, 255, 255))
gray_mask = np.all(input == 230, 2).astype(np.uint8)*255 # gray_mask = cv2.inRange(input, (230, 230, 230), (230, 230, 230))
mask = cv2.bitwise_or(white_mask, gray_mask) # Create unified mask
ctns = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # Find contours
# Remove small contours from mask
for c in ctns:
area = cv2.contourArea(c) # Find the area of each contours
if (area < 10): # Ignore small contours (assume noise).
cv2.drawContours(mask, [c], 0, 0, -1)
mask = cv2.dilate(mask, np.ones((3, 3), np.uint8)) # Dilate the mask - "cosmetics"
output = cv2.copyTo(input, 255-mask) # Put black color in the masked part.
# Show images for testing
cv2.imshow('input', input)
cv2.imshow('mask', mask)
cv2.imshow('output', output)
cv2.waitKey()
cv2.destroyAllWindows()
white_mask:
gray_mask:
mask:
output:
In case there are large white areas or gray areas in the foreground part, the above solution may not work.
I thought of a process for finding only the areas that overlaps a boundary between white and gray rectangle.
It's not working, because there are small parts between the tree branches that are excluded.
The following code may give you inspirations:
import cv2
import numpy as np
input = cv2.imread('image.png')
#ret, logo_mask = cv2.threshold(input[:,:,0], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
white_mask = np.all(input == 255, 2).astype(np.uint8)*255 # cv2.inRange(input, (255, 255, 255), (255, 255, 255))
gray_mask = np.all(input == 230, 2).astype(np.uint8)*255 # gray_mask = cv2.inRange(input, (230, 230, 230), (230, 230, 230))
cv2.imwrite('white_mask.png', white_mask)
cv2.imwrite('gray_mask.png', gray_mask)
# Apply opening for removing small clusters
opened_white_mask = cv2.morphologyEx(white_mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
opened_gray_mask = cv2.morphologyEx(gray_mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
cv2.imwrite('opened_white_mask.png', opened_white_mask)
cv2.imwrite('opened_gray_mask.png', opened_gray_mask)
white_mask_shell = cv2.dilate(opened_white_mask, np.ones((3, 3), np.uint8)) - opened_white_mask # Dilate white_mask and keep only the "shell"
gray_mask_shell = cv2.dilate(opened_gray_mask, np.ones((3, 3), np.uint8)) - opened_gray_mask # Dilate gray_mask and keep only the "shell"
white_mask_shell = cv2.dilate(white_mask_shell, np.ones((3, 3), np.uint8)) # Dilate the "shell"
gray_mask_shell = cv2.dilate(gray_mask_shell, np.ones((3, 3), np.uint8)) # Dilate the "shell"
cv2.imwrite('white_mask_shell.png', white_mask_shell)
cv2.imwrite('gray_mask_shell.png', gray_mask_shell)
overlap_shell = cv2.bitwise_and(white_mask_shell, gray_mask_shell)
cv2.imwrite('overlap_shell.png', overlap_shell)
dilated_overlap_shell = cv2.dilate(overlap_shell, np.ones((17, 17), np.uint8))
mask = cv2.bitwise_or(cv2.bitwise_and(white_mask, dilated_overlap_shell), cv2.bitwise_and(gray_mask, dilated_overlap_shell))
cv2.imshow('input', input)
cv2.imshow('white_mask', white_mask)
cv2.imshow('gray_mask', gray_mask)
cv2.imshow('white_mask', white_mask)
cv2.imshow('gray_mask', gray_mask)
cv2.imshow('opened_white_mask', opened_white_mask)
cv2.imshow('opened_gray_mask', opened_gray_mask)
cv2.imshow('overlap_shell', overlap_shell)
cv2.imshow('dilated_overlap_shell', dilated_overlap_shell)
cv2.imshow('mask', mask)
cv2.waitKey()
cv2.destroyAllWindows()
so my code is using opencv with tesseract to extract a text from a image
and what i want to do is to blacklist some parts of the image so the code don't check if there is a text here
the code :
import numpy as np
img = cv2.imread('test.jpeg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
sensitivity = 70
lower_range = np.array([0,0,255-sensitivity])
upper_range = np.array([255,sensitivity,255])
mask = cv2.inRange(hsv, lower_range, upper_range)
cv2.imshow('image', img)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
Base image:
Parts of the image i want to blacklist (in red):
can someone help me doing this if this is possible ?
Your objective here is to extract only the text from the resulting mask image and you already did most of the heavy lifting. I have tried using easyOCR library on mask which gives the result you are looking for.
Using mask as input image, here is the remaining code:
# import library and initialize the reader
from easyocr import Reader
reader = Reader(['en'])
# pass input image
results = reader.readtext(mask)
Output:
[([[93, 85], [245, 85], [245, 129], [93, 129]], 'SWHSY', 0.9746386534414473)]
It returns the bounding box position of the text, the text itself along with confidence score.
The following snippet allows you to draw the bounding box around the detected text:
for (bbox, text, prob) in results[:5]:
(tl, tr, br, bl) = bbox
top_left = (int(tl[0]), int(tl[1]))
bottom_right = (int(br[0]), int(br[1]))
img = cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 3)
img = cv2.putText(img, text, (tl[0], tl[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1.1, (255, 255, 0), 5)
I am making a application in python that allows people to share their screens, but in order to get a decent frame rate I wanted to compress the image into a grayscale format and then on the client side turn it back into an RGB image. But when I tried to do that it still showed a grayscale image.
Then I tried using HSV color conversion which did display the color, but with a red filter for some reason.
I won't show all of the code due to the fact it is at least 2000 lines, but I will show what part of the code where I am having my problem.
Server side:
sct_img = sct.grab(bounding_box)
img_np = np.array(sct_img)
frame = img_np
frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
frame = cv2.resize(frame, (0,0), fx = 0.70, fy = 0.70)
data = pickle.dumps(frame)
message_size = struct.pack("L", len(data))
clientsocket.sendall(message_size + data)
Client side:
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
frame = cv2.resize(frame, (x, y))
cv2.imshow('frame', frame)
When you convert an RGB image to grayscale, color data gets thrown away, hence you won't be able to get the original image back. Observe the output from code below:
import cv2
import numpy as np
# Create image
img = np.full((500, 500, 3), 255, 'uint8')
cv2.rectangle(img, (50, 100), (250, 300), (0, 0, 96), -1)
cv2.circle(img, (300, 350), 100, (0, 50, 0), -1)
cv2.drawContours(img, [np.array([(300, 50), (200, 250), (400, 250)])], 0, (255, 0, 0), -1)
# Convert to grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(np.unique(img_gray))
# Show images
cv2.imshow("BGR", img)
cv2.imshow("Gray", img_gray)
cv2.waitKey(0)
Output:
As you can see, with the image of a red, green and blue shape (each a specific shade of its color), converting it into grayscale results in the three colors turning into one; (29, 29, 29). There is no way the computer will be able to tell that the three shapes used to be different colors.
When you reduce a color image to grayscale, you're discarding information. There's no way to get color back. If you want to get an acceptable frame rate, you're going to have to choose some other approach.
I have an image with a black background. How am I supposed to draw a red shape on it? The red color should be (0,0,255) right? But it shows as black so it's not visible with a black background. The best I could do was to create a white rectangle in the following example. My question is how should I make it red? I think I'm missing something simple here. Please help.
import cv2
import numpy as np
img = np.zeros((500,500,1), np.uint16)
cv2.rectangle(img, (200, 200), (300, 300), (0, 0, 255), 5)
cv2.imshow('image',img)
cv2.waitKey(100000)
You will see the rectangle doesn't even show up:
And the best I could do was a white rectangle like this:
img = np.zeros((500,500,1), np.uint16)
cv2.rectangle(img, (200, 200), (300, 300), (2**16, 0, 0), 5)
cv2.imshow('image',img)
cv2.waitKey(100000)
You are trying to draw color (3 channels) on a black (one channel) image. You need to convert the black image to 3 channels. Here is how I do it in Python/OpenCV
import cv2
import numpy as np
# create one channel black image (grayscale)
img = np.zeros((500,500))
# convert to 3 channel black (color)
img = cv2.merge([img,img,img])
# draw on it in color
cv2.rectangle(img, (200, 200), (300, 300), (0, 0, 255), 5)
cv2.imshow('image',img)
cv2.waitKey(0)
The result is a red square outline on black background
Coded in Python. I have the following image that I classified with making so only what was found to have its original colour. Is there a way I can intensify the pixels colour (mage the green...greener)?
Goal is this:
img = cv2.imread("/Volumes/EXTERNAL/ClassifierImageSets/Origional_2.png",1)
mask = cv2.imread("/Users/chrisradford/Documents/School/Masters/RA/Classifier/Python/mask.png",0)
result = cv2.bitwise_and(img,img,mask=mask)
I convert it to HSV colorspace, and increment the S channel value to the max for the values that are "green".
with this code:
import cv2
img = cv2.imread("D:\\testing\\test.png",1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
greenMask = cv2.inRange(hsv, (26, 10, 30), (97, 100, 255))
hsv[:,:,1] = greenMask
back = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow('test', back)
cv2.waitKey(0)
cv2.destroyAllWindows()
If you want, you can put pure green to it like this:
with this code:
import cv2
img = cv2.imread("D:\\testing\\test.png",1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
greenMask = cv2.inRange(hsv, (26, 10, 30), (97, 100, 255))
img[greenMask == 255] = (0, 255, 0)
cv2.imshow('test', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
It seems that a part of the small thing in the south is also green (or green enough).
I hope this helps you.