Recognizing overlapping objects - python-3.x

I am processing an image with OpenCV on Python and I want to count every objects (worms) on it. Worms are rather light beige whereas the background is black (see picture) so it is rather easy to distinguish them. The problem is that sometimes worms are too close to each other (sometimes they even overlap) and cv.findContours() will draw one big contour instead of two smaller ones (see picture below).
Because I am using cv.foundContours(), I have to first turn the picture into black and white, then blur it (optional) and finally threshold it in order to have white worms in a black background.
I am using the following code :
import cv2 as cv
img = cv.imread('worms.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
blur=cv.GaussianBlur(gray,(5,5),1)
ret,osu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
imsource,contours,test = cv.findContours(osu,1,1)
cv.drawContours(img,contours,-1, (0,0,255),2)
I tried to erode the thresholded picture but it doesn't work well since the "bond" between two worms is quite big.
Thanks for the help

Related

I am trying to find the defects in following images. Not sure where to begin

`This has color defect.
This has crack defect.
This has scratch defect.
This has imprinting defect
input_img = cv2.resize(input_img,(500,500),interpolation=cv2.INTER_LINEAR)
gray_i_image = cv2.cvtColor(input_img, cv2.COLOR_BGR2GRAY)
blur_image = cv2.blur(gray_i_image,(3,3))
`
This is what I know in which I am resizing the image, then converting it to grey scale and then clearing the noise from data image. After that I don't know what to do.
I want an output image in which the defected area is highlighted as in rectangle, I know we have to use contours for it. but I dont know how to.

How to add border to an image, choosing color dynamically based on image edge color(s)?

I need to add a border to each image in a set of tightly cropped logos. The border color should either match the most commonly used color along the edge, OR, if there are too many different edge colors, it should choose some sort of average of the edge colors.
Here's an example. In this case, I would want the added border to be the same color as the image "background" (using that term in the lay sense). A significant majority of the pixels along the edges are that color, and there are only two other colors, so the decision algorithm would be able to select that rather drecky greenish tan for the added border (not saying anything bad about the organization behind the logo, mind you).
Does Pillow have any functions to simplify this task?
I found answers that show how to use Pillow to add borders and how to determine the average color of an entire image. But I couldn't find any code that looks only at the edges of an image and finds the predominant color, which color could then be used in the border-adding routine. Just in case someone has already done that work, please point me to it. ('Edges' meaning bands of pixels along the top/bottom/left/right margins of the image, whose height or width would be specified as a percentage of the image's total size.)
Short of pointing me to a gist that solves my whole problem, are there Pillow routines that look at edges and/or that count the colors in a pixel range and put them into an array or what not?
I see here that OpenCV can add a border the duplicates the color of the each outermost pixel along all four edges, but that looks funky—I want a solid-color border. And I'd prefer to stick with Pillow—unless another library can do the whole edge-color-analysis-and-add-border procedure in one step, more or less, in which case, please point it out.
Overwrite the center part of the image with some fixed color, that – most likely – won't be present within the edge. For that, maybe use a color with a certain alpha value. Then, there's a function getcolors, which exactly does, what you're looking for. Sort the resulting list, and get the color with the highest count. (That, often, will be the color we used to overwrite the center part. So check for that, and take the second entry, if needed.) Finally, use ImageOps.expand to add the actual border.
That'd be the whole code:
from PIL import Image, ImageDraw, ImageOps
# Open image, enforce RGB with alpha channel
img = Image.open('path/to/your/image.png').convert('RGBA')
w, h = img.size
# Set up edge margin to look for dominant color
me = 3
# Set up border margin to be added in dominant color
mb = 30
# On an image copy, set non edge pixels to (0, 0, 0, 0)
img_copy = img.copy()
draw = ImageDraw.Draw(img_copy)
draw.rectangle((me, me, w - (me + 1), h - (me + 1)), (0, 0, 0, 0))
# Count colors, first entry most likely is color used to overwrite pixels
n_colors = sorted(img_copy.getcolors(2 * me * (w + h) + 1), reverse=True)
dom_color = n_colors[0][1] if n_colors[0][1] != (0, 0, 0, 0) else n_colors[1][1]
# Add border
img = ImageOps.expand(img, mb, dom_color).convert('RGB')
# Save image
img.save('with_border.png')
That'd be the result for your example:
And, that's some output for another image:
It's up to you to decide, whether there are several dominant colors, which you want to mix or average. You'd need to inspect the n_colors appropriately on the several counts for that. That's quite a lot of work, which is left out here.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
PyCharm: 2021.1
Pillow: 8.2.0
----------------------------------------

Why is a generated SVG image less rich than the corresponding PNG image

To set this up, I used svgwrite library to create a sample SVG image (20 squares of length 100 at random locations on a display size of length 400)
import svgwrite
import random
random.seed(42)
dwg = svgwrite.Drawing('x.svg', size=(400,400))
dwg.add(dwg.rect(insert=(0,0), size=('100%', '100%'), fill='white')) # White background
for i in range(20):
coordinates = (random.randint(0,399), random.randint(0,399))
color = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
dwg.add(dwg.rect(coordinates, (100, 100),
stroke='black',
fill=svgwrite.rgb(*color),
stroke_width=1)
)
dwg.save()
I then wrote a sample pygame program to generate a PNG image of the same sample. (A seed has been used to generate the same sequence of squares.)
import pygame
import random
random.seed(42)
display = pygame.display.set_mode((400,400))
display.fill((255,255,255)) # White background
for i in range(20):
coordinates = (random.randint(0,399), random.randint(0,399))
color = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
pygame.draw.rect(display, color, coordinates+(100,100), 0)
pygame.draw.rect(display, (0,0,0), coordinates+(100,100), 1) #For black border
pygame.image.save(display, "x.png")
These are the images that I got (SVG's can't be uploaded to SO, so I have provided a screenshot. Nevertheless, the programs above can be run to output the same).
My question is, why is the PNG (on the left) richer and sharper than the corresponding SVG image? The SVG looks blurred and bland, comparatively.
EDIT: One can notice the fine white line between the first two squares at the top-left corner. It's not very clear in the SVG.
Two things I think may impact:
You are using an image viewer, which could distort the vectorial SVG image. I think all of the vector images viewers get the actual screen size, then export the vectorial image into a matrix image sized in function of the size of the screen you have. Then they display the matrix image. If they render the image with softened sharpness, or if they have a problem by getting the size of your screen, the image may be blurred.
To make the PNG image, you use pygame. But you are using another module to make the SVG image. This module may function differently, and also exports the image with another quality than if you were exporting it with pygame.
For me personally the SVG image appears blurred with Gimp, for example, but not with another SVG viewer.
So I think the problem comes from your image viewer.

Remove the picture edges

I downloaded a icon, and now i want to reset the color of it, but i'm not good at photoshop, i've set the color of it to be red, but there are to many edges and corners, please tell me how to remove those edges by using photoshop step by step, thanks a lot.
here is the icon i downloaded:
and this is my ugly one:
The best way to alter a single color like this on a simple image such as this is to alter the Hue and Saturation [CTRL / CMD + U]...
This allows you greater color control and keeps the anti-aliased edges of the image intact.
Most beginners alter colors like this by simply selecting the color with the wand, or using the paint bucket on the color. Unfortunately this usually does one of 2 things:
Makes the ragged edges that you saw.
Leaves a halo of the old color as an orphan.
I did this in a few seconds with that tool:

Color Space Inversion for contrasting grid

I have a randomly colored background that is split into solid colored rectangles. I want to draw a grid over the rectangles (this is not the problem). The issue is because of the random colors I cannot hard-code the grid color because it may not show up.
Another way to think about this is plotting a grid on a plot of a surface f(x,y). If the grid color happens to be the same color of the function (however it is defined) then it won't be visible.
I would like to take the background color and compute a new color (either grayscale or similar to the background color) that is contrasted with the color so it can easily be seen (but not distracting such as pure white on pure black).
I've tried using the luminance and weighted luminance but it doesn't work well for all colors. I've also tried gamma correcting the colors but it also does not work well.
I would also like the grid color to be as uniform as possible (I could possibly compute the adjacent grid colors to blend in). It is not that important but would be nice to have some uniformity.
The code I'm working with is based around
//byte I = (byte)(0.2*R + 0.7*G + 0.1*B);
//byte I = (byte)(R + G + B)/3.0);
byte I = (byte)(Math.Max(Bar.Background.R, Math.Max(Bar.Background.G, Bar.Background.B)));
if (I < 120)
I = (byte)(I + 30);
else
I = (byte)(I - 30);
//I = (byte)(Math.Pow(I/255.0, 1/2.0)*255);
I've also tried gamma correcting the rgb's first.
Anyone have any ideas?
The colors that offer the most contrast are colors that are fully saturated. This offers you a way to find color that may work(but not necessarily for many reasons). Essentially you pick the color the furthest away along the line connecting color and the fully saturated color.

Resources