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
Related
I am loading a partially-transparent image into pygame and cropping it the following way:
img = pygame.image.load(image_url).convert_alpha()
cropped_img = pygame.Surface((100, 100)).convert_alpha()
cropped_img.blit(img, (0, 0))
The transparent sections of the image are seen as black. set_colorkey((0, 0, 0)) makes the black transparent, but it also makes the black in the image transparent. How would I only get rid of the transparency-caused black?
The line
cropped_img = pygame.Surface((100, 100)).convert_alpha()
does not create a transparent image. pygame.Surface((100, 100)) generates a completely black image. convert_alpha() does not change that. If you create a new surface and use convert_alpha(), the alpha channels are initially set to maximum. The initial value of the pixels is (0, 0, 0, 255)
If you want to crate a transparent image, you have 2 options. Either set a black color key with pygame.Surface.set_colorkey, before converting the foramt of the Surface:
cropped_img = pygame.Surface((100, 100))
cropped_img.set_colorkey(0)
cropped_img = cropped_img.convert_alpha()
or use the SRCALPHA flag to create a Surface with a per pixel alpha format.
cropped_img = pygame.Surface((100, 100), pygame.SRCALPHA)
Final code:
img = pygame.image.load(image_url).convert_alpha()
cropped_img = pygame.Surface((100, 100), pygame.SRCALPHA)
cropped_img.blit(img, (0, 0))
I am trying to detect circles in an antibiotic susceptibility test image. with my code, it detects 7 circles however it draws way too many of them (you can find the original image and the results in the links bellow) . how can I make the detection accurate?
P.S: I know that the minRadius i want to detect is 20mm≈75pixels and maxRad is 50mm≈190pixels
import cv2
import numpy as np
image= "atbg.jpg"
img= cv2.imread(image,1)
img_orig=img.copy()
img= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(img,(21,21),cv2.BORDER_DEFAULT)
all_circs=cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,10, param1=50, param2=30, minRadius=75 , maxRadius=190)
all_circs_rounded= np.uint16(np.around(all_circs))
for (x, y ,r) in all_circs_rounded[0, :]:
cv2.circle(img_orig, (x, y), r, (0, 0, 0), 3)
cv2.circle(img_orig, (x, y), 2, (0, 255, 255), 3)
imS = cv2.resize(img_orig, (600, 540))
cv2.imshow("output", imS)
cv2.waitKey(0)
cv2.destroyAllWindows()
Original image:
Result image:
Can you first get the edges of the circles using Canny() edge detection?
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()
I am trying to make a transparent image and draw on it, and after I will addWeighted over the base image.
How can I initialize fully transparent image with width and hight in openCV python?
EDIT: I want to make a effect like in Photoshop, having stack of the layers, all stacked layers are initially transparent and drawing is performed on fully transparent layer. On the end I will merge all layers to get final image
For creating a transparent image you need a 4 channel matrix, 3 of which would represent RGB colors and the 4th channel would represent Alpha channel, To create a transparent image, you can ignore the RGB values and directly set the alpha channel to be 0. In Python OpenCV uses numpy to manipulate matrices, so a transparent image can be created as
import numpy as np
import cv2
img_height, img_width = 300, 300
n_channels = 4
transparent_img = np.zeros((img_height, img_width, n_channels), dtype=np.uint8)
# Save the image for visualization
cv2.imwrite("./transparent_img.png", transparent_img)
If you want to draw on several "layers" and then stack the drawings together, then how about this:
import cv2
import numpy as np
#create 3 separate BGRA images as our "layers"
layer1 = np.zeros((500, 500, 4))
layer2 = np.zeros((500, 500, 4))
layer3 = np.zeros((500, 500, 4))
#draw a red circle on the first "layer",
#a green rectangle on the second "layer",
#a blue line on the third "layer"
red_color = (0, 0, 255, 255)
green_color = (0, 255, 0, 255)
blue_color = (255, 0, 0, 255)
cv2.circle(layer1, (255, 255), 100, red_color, 5)
cv2.rectangle(layer2, (175, 175), (335, 335), green_color, 5)
cv2.line(layer3, (170, 170), (340, 340), blue_color, 5)
res = layer1[:] #copy the first layer into the resulting image
#copy only the pixels we were drawing on from the 2nd and 3rd layers
#(if you don't do this, the black background will also be copied)
cnd = layer2[:, :, 3] > 0
res[cnd] = layer2[cnd]
cnd = layer3[:, :, 3] > 0
res[cnd] = layer3[cnd]
cv2.imwrite("out.png", res)
To convert an image's white parts to transparent:
import cv2
import numpy as np
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
img[np.where(np.all(img[..., :3] == 255, -1))] = 0
cv2.imwrite("transparent.png", img)
I have a png image as background and I want to add a transparent mesh to this background but this doesn't work as expected. The background image is converted to transparent on places where I apply transparent mesh.
I am doing:
from PIL import Image, ImageDraw
map_background = Image.open(MAP_BACKGROUND_FILE).convert('RGBA')
map_mesh = Image.new('RGBA', (width, height), (0, 0, 0, 0))
draw = ImageDraw.Draw(map_mesh)
# Create mesh using: draw.line([...], fill=(255, 255, 255, 50), width=1)
...
map_background.paste(map_mesh, (0, 0), map_mesh)
But the result is:
You can see a chessboard pattern if you look carefully (used in graphics programs as no background). Transparent lines makes the background layer transparent too in places where both layers met. But I only want the transparent line to be added on top of the background.
I can solve it with:
map_background.paste((255,255,255), (0, 0), map_mesh)
but as I use different colors for different lines, I would have to make for every color this process. If I had 100 colors, then I need 100 layers what is not very good solution.
What you are trying to do is to composite the grid onto the background, and for that you need to use Image.blend or Image.composite. Here's an example using the latter to composite red lines with random alpha values onto a white background:
import Image, ImageDraw, random
background = Image.new('RGB', (100, 100), (255, 255, 255))
foreground = Image.new('RGB', (100, 100), (255, 0, 0))
mask = Image.new('L', (100, 100), 0)
draw = ImageDraw.Draw(mask)
for i in range(5, 100, 10):
draw.line((i, 0, i, 100), fill=random.randrange(256))
draw.line((0, i, 100, i), fill=random.randrange(256))
result = Image.composite(background, foreground, mask)
From left to right:
[background] [mask]
[foreground]
[result]
(If you are happy to write the result back to the background image, then you can use one of the masked versions of Image.paste, as pointed out by Paulo Scardine in a deleted answer.)
I had trouble getting the above examples to work well. Instead, this worked for me:
import numpy as np
import Image
import ImageDraw
def add_craters(image, craterization=20.0, width=256, height=256):
foreground = Image.new('RGBA', (width, height), (0, 0, 0, 0))
draw = ImageDraw.Draw(foreground)
for c in range(0, craterization):
x = np.random.randint(10, width-10)
y = np.random.randint(10, height-10)
radius = np.random.randint(2, 10)
dark_color = (0, 0, 0, 128)
draw.ellipse((x-radius, y-radius, x+radius, y+radius), fill=dark_color)
image_new = Image.composite(foreground, image, foreground)
return image_new