overlay image mask equivalent in CV2 [duplicate] - python

Please look at this github page. I want to generate heat maps in this way using Python PIL,open cv or matplotlib library. Can somebody help me figure it out?
I could create a heat map for my network at the same size as the input, but I am not able superimpose them. The heatmap shape is (800,800) and the base image shape is (800,800,3)

Updated Answer -- 29th April, 2022.
After the repeated comments I have decided to update this post with a better visualization.
Consider the following image:
img = cv2.imread('image_path')
I obtained a binary image after performing binary threshold on the a-channel of the LAB converted image:
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_component = lab[:,:,1]
th = cv2.threshold(a_component,140,255,cv2.THRESH_BINARY)[1]
Applying Gaussian blur:
blur = cv2.GaussianBlur(th,(13,13), 11)
The resulting heatmap:
heatmap_img = cv2.applyColorMap(blur, cv2.COLORMAP_JET)
Finally, superimposing the heatmap over the original image:
super_imposed_img = cv2.addWeighted(heatmap_img, 0.5, img, 0.5, 0)
Note: You can vary the weight parameters in the function cv2.addWeighted and observe the differences.

My code starts from a heatmap matrix (224,224) called cam, which is applied to the original image called frame, via opencv;
and it seems to work pretty well:
import numpy as np
from cv2 import cv2
from skimage import exposure
...
capture = cv2.VideoCapture(...)
while True:
ret, frame = capture.read()
if ret:
#resize original frame
frame = cv2.resize(frame, (224, 224))
#get color map
cam = getMap(frame)
map_img = exposure.rescale_intensity(cam, out_range=(0, 255))
map_img = np.uint8(map_img)
heatmap_img = cv2.applyColorMap(map_img, cv2.COLORMAP_JET)
#merge map and frame
fin = cv2.addWeighted(heatmap_img, 0.5, frame, 0.5, 0)
#show result
cv2.imshow('frame', fin)
the getMap() function gets the headmap given the frame;
I found some interesting free videos about this topic:
https://www.youtube.com/watch?v=vTY58-51XZA&t=14s
https://www.youtube.com/watch?v=4v9usdvGU50&t=208s

I had some problems with grayscale images at this line
super_imposed_img = cv2.addWeighted(heatmap_img, 0.5, img, 0.5, 0)
but this one worked for me
plt.imshow(binary_classification_result * 0.99 + original_gray_image * 0.01)

Related

how to apply colormap to grayscale data, with OpenCV

I have a np.array with grayscale images and I want to apply a colormap, then save the result into a video file.
With this code (or with the commented line) I get a grayscale video anyways. Any idea why I can't have a colormap video?
color_images = np.empty([N, resolution[1], resolution[0], 3])
for i in range(0, N):
cv2.imwrite(gray_images[i])
color_images[i] = cv2.cvtColor(np.float32(gray_images[i]), cv2.COLOR_GRAY2BGR)
#color_images[i] = cv2.merge([gray_images[i], gray_images[i], gray_images[i]])
out = cv2.VideoWriter("video.mp4", cv2.VideoWriter_fourcc(*'mp4v'),
fps, (resolution[0], resolution[1]), 1)
for i in range(0, N):
out.write(np.uint8(color_images[i]))
out.release()
UPDATE: I want to have a colored image so that differences in pixel intensity can be more noticeable. (For instance use the default cmap in plt.imshow ('viridis')).
cvtColor doesn't do that. For any grayscale pixel, it gives you the RGB/BGR pixel that looks gray with the same intensity.
If you want colormaps, you need applyColorMap.
import numpy as np
import cv2 as cv
gray_image = ... # get it from somewhere
colormapped_image = cv.applyColorMap(gray_image, cv.COLORMAP_JET)
learn more here

Saving images with OpenCV and accumulateWeighted(...)

I'm new to OpenCV, so apologies if this is a trivial question...
I'm writing an application that tracks the path of an object in real time. So far, I have successfully isolated the object and created a "trail" of its path using cv2.accumulateWeighted(). Everything looks great in the preview window, but when I save the merged frame to a file, things aren't so good.
The result varies, but typically the saved frame has much less detail than the displayed frame. I've converted the input to grayscale, and often the written file has very "dim" features.
I believe only the final frame is written (multiplied by the alpha blend), rather than the accumulated image. Any ideas would be greatly appreciated.
Sample program to demonstrate the issue:
import cv2
#---- read the next frame from the capture device
def read_frame(cap):
ret, frame = cap.read()
if ret is False or frame is None:
return None
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
return gray_frame
#---- setup components
cap = cv2.VideoCapture(index=0)
background_subtractor = cv2.createBackgroundSubtractorMOG2(
history=30, varThreshold=50, detectShadows=False
)
#---- prime the accumulator
frame = read_frame(cap)
merged_frame = frame.astype(float)
#---- capture some frames
while True:
frame = read_frame(cap)
mask = background_subtractor.apply(frame, learningRate=0.01)
foreground = cv2.bitwise_and(frame, frame, mask=mask)
cv2.accumulateWeighted(foreground, merged_frame, 0.1)
cv2.imshow('Acccumulator', merged_frame)
key = cv2.waitKey(1)
# press 'q' to quit and save the current frame
if key == ord('q') or key == ord('Q'):
cv2.imwrite('merged.png', merged_frame)
break
The following are images when moving my hand through the scene... You can see the path of my hand in the displayed image, along with some other background elements. In the saved image, only a very dim version of my hand in the final position is saved.
This is the displayed image (using screen capture):
This is the image written to disk (using imwrite()):
I guess you want to save merged_frame as it shown by cv2.imshow.
You may limit the upper value of merged_frame to 1, scale by 255, and convert to uint8 type, before saving:
merged_frame = np.round(np.minimum(merged_frame, 1)*255).astype(np.uint8)
The type of merged_frame is float64.
When using cv2.imshow for image of type float, all the values above 1.0 are white (and below 0 are black).
Gray level of range [0, 1] is equivalent to range [0, 255] of uint8 type (0.5 is like 128).
When using cv2.imwrite the image is converted to uint8, but without clamping and scaling (simple cast to 255). The result is usually very dark.
In case you want to save the image as it shown, you need to clamp value to 1, then scale by 255.
You didn't post input samples, so I created synthetic input:
import numpy as np
import cv2
background_subtractor = cv2.createBackgroundSubtractorMOG2(
history=30, varThreshold=50, detectShadows=False
)
width, height = 640, 480
frame = np.full((height, width), 60, np.uint8)
merged_frame = frame.astype(float)
for n in range(100):
img = np.full((height, width, 3), 60, np.uint8)
cv2.putText(img, str(n), (width//2-100*len(str(n)), height//2+100), cv2.FONT_HERSHEY_DUPLEX, 10, (30, 255, 30), 20) # Green number
#frame = read_frame(cap)
frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
mask = background_subtractor.apply(frame, learningRate=0.01)
foreground = cv2.bitwise_and(frame, frame, mask=mask)
cv2.accumulateWeighted(foreground, merged_frame, 0.1)
cv2.imshow('Acccumulator', merged_frame)
cv2.waitKey(10)
#merged_frame = cv2.normalize(merged_frame, merged_frame, 0, 255.0, cv2.NORM_MINMAX).astype(np.uint8) # Alternative approch - normalize between 0 and 255
merged_frame = np.round(np.minimum(merged_frame, 1)*255).astype(np.uint8)
cv2.imshow('merged_frame as uint8', merged_frame)
cv2.imwrite('merged.png', merged_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
PNG image using imwrite, without camping and scaling:
PNG image using imwrite, with camping and scaling:
A better way for showing the image, is normalize the values to range [0, 1] before showing the image.
Example:
In the loop, after cv2.accumulateWeighted(foreground, merged_frame, 0.1):
norm_acccumulator = merged_frame.copy()
cv2.normalize(norm_acccumulator, norm_acccumulator, 0, 1.0, cv2.NORM_MINMAX)
cv2.imshow('Acccumulator', norm_acccumulator)

How to erase the dotted watermark from set of similar images?

I want to automate the task of entering set of images into a number generating system & before that i like to remove a dotted watermark which is common across these images.
I tried using google, tesseract & abby reader, but I found that the image part that does not contain the watermark is recognized well, but the part that is watermarked is almost impossible to recognize.
I would like to remove the watermark using image processing. I already tried few sample codes of opencv, python, matlab etc but none matching my requirements...
Here is a sample code in Python that I tried which changes the brightness & darkness:
import cv2
import numpy as np
img = cv2.imread("d:\\Docs\\WFH_Work\\test.png")
alpha = 2.5
beta = -250
new = alpha * img + beta
new = np.clip(new, 0, 255).astype(np.uint8)
cv2.imshow("my window", new)
Unusually, i dont know the watermark of this image consists how many pixels. Is there a way to get rid of this watermark OR make digits dark and lower the darkness of watermark via code?
Here is watermarked image
I am using dilate to remove the figures, then find the edge to detect watermark. Remove it by main gray inside watermark
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('test.png', 0)
kernel = np.ones((10,10),np.uint8)
dilation = cv2.dilate(img,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
plt.imshow(erosion, cmap='gray')
plt.show()
#contour
gray = cv2.bilateralFilter(erosion, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)
plt.imshow(edged, cmap='gray')
plt.show()

Using local average color of image to reduce difference in lightning

I am new to opencv and I am currently working on 'Diabetic Retinopathy Detection' (a kaggle competition was launched 3 years ago; more details here : https://www.kaggle.com/c/diabetic-retinopathy-detection/data). Currently, I am trying to achieve similar results on image processing as depicted in the image below (source: http://blog.kaggle.com/2015/09/09/diabetic-retinopathy-winners-interview-1st-place-ben-graham/):
Now I have tried different approaches including histogram equalization and Contrast Limited Adaptive Histogram Equalization (CLAHE). CLAHE gives the best results so far, but nothing compared to the images above. I got some ideas from here : (How to remove the local average color from an image with OpenCV) but couldn't reproduce the results. If someone can guide me how it can be done with opencv or any other python vision library, it would be great. Sample images can be downloaded from kaggle site (link mentioned above). Thanks.
Here is my code so far:
def equalize_hist(input_path):
img = cv.imread(input_path)
for c in range(0, 2):
img[:,:,c] = cv.equalizeHist(img[:,:,c])
cv.imshow('Histogram equalized', img)
cv.waitKey(0)
cv.destroyAllWindows()
def clahe_rgb(input_path):
bgr = cv.imread(input_path)
lab = cv.cvtColor(bgr, cv.COLOR_BGR2LAB)
lab_planes = cv.split(lab)
gridsize = 5
clahe = cv.createCLAHE(clipLimit=2.0,tileGridSize=(gridsize,gridsize))
lab_planes[0] = clahe.apply(lab_planes[0])
lab = cv.merge(lab_planes)
bgr2 = cv.cvtColor(lab, cv.COLOR_LAB2BGR)
cv.imshow('CLAHE RGB', bgr2)
cv.waitKey(0)
cv.destroyAllWindows()
def clahe_greyscale(input_path):
img = cv.imread(input_path)
gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(gray_image)
cv.imshow('CLAHE Grayscale', cl1)
cv.waitKey(0)
cv.destroyAllWindows()
The code you show is doing a local histogram equalization, whereas the highlighted text you posted talks about removing the average color from each pixel.
Removing the average color could be done like this:
# Blur the image
blurred = cv2.blur(img, ksize=(15, 15))
# Take the difference with the original image
# Weight with a factor of 4x to increase contrast
dst = cv2.addWeighted(img, 4, blurred, -4, 128)
You can adjust the kernel size of the blur code (above it's 15) to find something that works for your use case.
You may need to downscale the images to a common size before doing this, to get comparable results (as also noted in the blog post you cite).

How to resize output images in python?

Hi i run this blurdetection code in python ( source : https://www.pyimagesearch.com/2015/09/07/blur-detection-with-opencv/ )
# import the necessary packages
from imutils import paths
import argparse
import cv2
def variance_of_laplacian(image):
# compute the Laplacian of the image and then return the focus
# measure, which is simply the variance of the Laplacian
return cv2.Laplacian(image, cv2.CV_64F).var()
# loop over the input images
for imagePath in paths.list_images("images/"):
# load the image, convert it to grayscale, and compute the
# focus measure of the image using the Variance of Laplacian
# method
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
fm = variance_of_laplacian(gray)
text = "Not Blurry"
# if the focus measure is less than the supplied threshold,
# then the image should be considered "blurry"
if fm < 100:
text = "Blurry"
# show the image
cv2.putText(image, "{}: {:.2f}".format(text, fm), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3)
cv2.imshow("Image", image)
print("{}: {:.2f}".format(text, fm))
key = cv2.waitKey(0)
with this 2173 x 3161 input file
input image
and this is the output show
the output image
The image is zoom in and dont shown full.
In the source code, they use 450 x 600 px input image :
input in source code
and this is the output :
output in source code
I think the pixels of the image influences of the output. So, how can i get the output like the output in source code to all image?
do i have to resize the input image? How to? but if I do it I'm afraid it will affect the result of his blur
Excerpt from the DOCUMENTATION.
There is a special case where you can already create a window and load image to it later. In that case, you can specify whether window is resizable or not. It is done with the function cv2.namedWindow(). By default, the flag is cv2.WINDOW_AUTOSIZE. But if you specify flag to be cv2.WINDOW_NORMAL, you can resize window. It will be helpful when image is too large in dimension and adding track bar to windows.
I just used the code placed in the question but added line cv2.namedWindow("Image", cv2.WINDOW_NORMAL) as mentioned in the comments.
# import the necessary packages
from imutils import paths
import argparse
import cv2
def variance_of_laplacian(image):
# compute the Laplacian of the image and then return the focus
# measure, which is simply the variance of the Laplacian
return cv2.Laplacian(image, cv2.CV_64F).var()
# loop over the input images
for imagePath in paths.list_images("images/"):
# load the image, convert it to grayscale, and compute the
# focus measure of the image using the Variance of Laplacian
# method
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
fm = variance_of_laplacian(gray)
text = "Not Blurry"
# if the focus measure is less than the supplied threshold,
# then the image should be considered "blurry"
if fm < 100:
text = "Blurry"
# show the image
cv2.putText(image, "{}: {:.2f}".format(text, fm), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3)
cv2.namedWindow("Image", cv2.WINDOW_NORMAL) #---- Added THIS line
cv2.imshow("Image", image)
print("{}: {:.2f}".format(text, fm))
key = cv2.waitKey(0)
In case you want to use the exact same resolution as the example you've given, you can just use the cv2.resize() https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#resize method or (in case you want to keep the ratio of the x/y coordinates) use the imutils class provided in https://www.pyimagesearch.com/2015/02/02/just-open-sourced-personal-imutils-package-series-opencv-convenience-functions/
You still have to decide if you want to do the resizing first. It shouldn't matter in which order you greyscale or resize.
Command you can add:
resized_image = cv2.resize(image, (450, 600))

Categories

Resources