How can I do template matching in opencv with colour? - numpy

I have been trying to use opencv's template matching function to match templates within images. However, when the images are dark brown and dark green, the template matching does not work so well. I am pretty sure it is the grey scale conversion that is responsible for this because in greyscale it looks very similar.
However from what I see, cv2.matchtemplate() only takes in grey scale images. How can I do coloured template matching? Should I seperate the RGB image into 3 images: one red, one green, one blue and treat each one as gray scale images and apply matchtemplate then sum the similarity rating for each pixel position? Is that the way to do it? Or is there a different function or a parameter value I can use to make matchtemplate work for coloured images?

You may try this code:
import numpy as np
import cv2
threshold = 0.8
##Read Main and Needle Image
imageMainRGB = cv2.imread(main/Image/Path/main.png)
imageNeedleRGB = cv2.imread(needle/Image/Path/needle.png)
##Split Both into each R, G, B Channel
imageMainR, imageMainG, imageMainB = cv2.split(imageMainRGB)
imageNeedleR, imageNeedleG, imageNeedleB = cv2.split(imageNeedleRGB)
##Matching each channel
resultB = cv2.matchTemplate(imageMainR, imageNeedleR, cv2.TM_SQDIFF)
resultG = cv2.matchTemplate(imageMainG, imageNeedleG, cv2.TM_SQDIFF)
resultR = cv2.matchTemplate(imageMainB, imageNeedleB, cv2.TM_SQDIFF)
##Add together to get the total score
result = resultB + resultG + resultR
loc = np.where(result >= 3 * threshold)
print("loc: ", loc)
The Image I tested with are:
main.png
needle.png
result.png
Remark: This code may not function in some photos, where a user may need to modify it further to enhance it.
Note: This image was getting from pexels.com which is free copyright. If you have any issues with the image copyright and want to take down this image, welcome to contact me. Thanks.

Related

Selecting circular region of interest w/ Python

I am trying to write a program that can circle / mark out 5 distinct regions of interest in an image with a white background. Essentially these are 5 experimental conditions, and ultimately I would like to analyse the intensities of these conditions. 5 circles with varying flourescence levels (red)Another example, but this time with yellow
What I want to achieve is something that can circle / mark out the regions, as seen in the image below. All 5 regions marked out -- I did this manually. I have written some code using cv2, but I haven't been able to obtain desirable results.
import cv2
import numpy as np
experiment = cv2.imread('image.png')
gray = cv2.cvtColor(experiment, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray, 5)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 120, param1 = 100, param2 = 30, minRadius = 0, maxRadius = 0)
circles = np.uint(np.around(circles))
for i in circles[0, :]:
cv2.circle(experiment, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv2.imshow("Detection results", experiment)
cv2.waitKey(0)
cv2.destroyAllWindows()
My results / code output - wrong
For the yellow, only one condition is marked while the others aren't.
For red, only the second and fifth conditions are marked
How should I change my code to ensure all 5 conditions are marked, and what parameters should I change so the circle is strictly within the bounds of the liquid, and no white background is incorporated and will affect my flourescence quantification / analysis?
Additional notes:
1. All the images being analysed will have a white background and 5 distinct liquid drops, so I think HoughCircles can handle this and I don't need any fancy AI to detect the circles?
2. Ultimately I want to have this on a website where users can simply upload their experimental results and their 5 conditions can be circled, isolated and flourescence analysis done with code--- the entire process automated. That's why I don't want to use, for instance, the ROI manager in ImageJ/Fiji because that would require users to do everything manually.

Unusual Mesh Outline PColorMesh

I am utilizing the pcolormesh function in Matplotlib to plot a series of gridded data (in parallel) across multiple map domains. The code snippet relevant to this question is as follows:
im = ax2.pcolormesh(xgrid, ygrid, data.variable.data[0], cmap=cmap, norm=norm, alpha=0.90, facecolor=None)
Where: xgrid = array of longitude points, ygrid = array of latitude points, data.variable.data[0] = array of corresponding data values, cmap = defined colormap, & norm = defined value normalization
Consider the following image generated from the provided code:
The undesired result I've found in the image above is what appears to be outlines around each grid square, or perhaps better described as patchwork that stands out slightly as the mesh alpha is reduced below 1.
I've set facecolor=None assuming that would remove these outlines, to no avail. What additions or corrections can I make to remove this feature?

Subtract Blending Mode

I have been trying to implement some of the layer blending modes of GIMP (GEGL) to Python. Currently, I am stuck in Subtract Blending mode. As per documentation, Subtract = max(Background - Foreground, 0). However, doing a simple test in GIMP, with Background image = (205,36,50) and Foreground image = (125,38,85), the resultant composite image/colour comes to be (170, 234, 0) which doesn't quite follow the math above.
As per understanding, Subtract does not use Alpha Blending. So, could this be a compositing issue? Or Subtract follows different math? More details and background can be find in a separate SO question.
EDIT [14/10/2021]:
I tried with this image as my Source. Performed following steps on images normalised in range [0, 1]:
Applied a Colour Dodge (no prior conversion from sRGB -> linear RGB was done) and obtained this from my implementation which matches with GIMP result.
sRGB -> linear RGB conversion on Colour Dodge and Source image. [Reference]
Apply Subtract blending with Background = Colour Dodge and Foreground = Source Image
Reconvert linear RGB-> sRGB
I obtain this from POC. Left RGB triplet: (69,60,34); Right RGB triplet: (3,0,192). And the GIMP result. Left RGB triplet: (69,60,35); Right RGB triplet: (4,255,255)
If you are looking at channel values in the 0 ➞ 255 range they are likely gamma-corrected. The operation is possibly done like this:
convert each layer to "linear light" in the 0.0 ➞ 1.0 range using something like
L = ((V/255) ** gamma) (*)
apply the "difference" formula
convert the result back to gamma-corrected:
V = (255 * (Diff ** (1/gamma)))
With gamma=2.2 you obtain 170 for the Red channel, but I don't see why you get 234 on the Green channel.
(*) The actual formula has a special case for the very low values IIRC.

Comparing two images - Detect egg in a nest

I have a webcam directly over a chicken nest. This camera takes images and uploads them to a folder on a server. I'd like to detect if an egg has been laid from this image.
I'm thinking the best method would be to compare the contrast as the egg will be much more reflective than the straw nest. (The camera has Infrared so the image is partly grey scale)
I'd like to do this in .NET if possible.
Try to resize your image to a smaller size, maybe 10 x 10 pixel. This averages out any small disturbing details.
Const N As Integer = 10
Dim newImage As New Bitmap(N, N)
Dim fromCamera As Image = Nothing ' Get image from camera here
Using gr As Graphics = Graphics.FromImage(newImage)
gr.SmoothingMode = SmoothingMode.HighSpeed
gr.InterpolationMode = InterpolationMode.Bilinear
gr.PixelOffsetMode = PixelOffsetMode.HighSpeed
gr.DrawImage(fromCamera, New Rectangle(0, 0, N, N))
End Using
Note: you do not need a high quality, but you need a good averaging. Maybe you will have to test different quality settings.
Since now, a pixel covers a large area of your original image, a bright pixel is very likely part of an egg. It might also be a good idea to compare the brightness of the brightest pixel to the average image brightness, since that would reduce problems due to global illumination changes.
EDIT (in response to comment):
Your code is well structured and makes sense. Here some thoughts:
Calculate the gray value from the color value with:
Dim grayValue = c.R * 0.3 + c.G * 0.59 + c.B * 0.11
... instead of comparing the three color components separately. The different weights are due to the fact, that we perceive green stronger than red and red stronger than blue. Again, we do not want a beautiful thumbnail we want a good contrast. Therefore, you might want to do some experiments here as well. May be it is sufficient to use only the red component. Dependent on lighting conditions one color component might yield a better contrast than others. I would recommend, to make the gray conversion part of the thumbnail creation and to write the thumbnails to a file or to the screen. This would allow you to play with the different settings (size of the thumbnail, resizing parameters, color to gray conversion, etc.) and to compare the (intermediate) results visually. Creating a bitmap (bmp) with the (end-)result is a very good idea.
The Using statement does the Dispose() for you. It does it even if an exception should occur before End Using (There is a hidden Try Finally involved).

Objective C - Detect a "path" drawing, inside a map image

I have a physical map (real world), for example, a little town map.
A "path" line is painted over the map, think about it like "you are here. here's how to reach the train station" :)
Now, let's suppose I can get an image of that scenario (likewise, coming from a photo).
An image that looks like:
My goal is not easy way out!
I want to GET the path OUT of the image, i.e., separate the two layers.
Is there a way to extract those red marks from the image?
Maybe using CoreGraphics? Maybe an external library?
It's not an objective C specific question, but I am working on Apple iOS.
I already worked with something similar, the face-recognition.
Now the answer I expect is: "What do you mean by PATH?"
Well, I really don't know, maybe a line (see above image) of a completely different color from the 'major' colors in the background.
Let's talk about it.
If you can use OpenCV then it becomes simpler. Here's a general method:
Separate the image into Hue, Saturation and Variation (HSV colorspace)
Here's the OpenCV code:
// Compute HSV image and separate into colors
IplImage* hsv = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 );
cvCvtColor( img, hsv, CV_BGR2HSV );
IplImage* h_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
IplImage* s_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
IplImage* v_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
Deal with the Hue (h_plane) image only as it gives just the hue without any change in value for a lighter or darker shade of the same color
Check which pixels have Red hue (i think red is 0 degree for HSV, but please check the OpenCV values)
Copy these pixels into a separate image
I's strongly suggest using the OpenCV library if possible, which is basically made for such tasks.
You could filter the color, define a threshold for what the color red is, then filter everything else to alpha, and you have left over what your "path" is?