I am looking for a method to detect blurry areas in an image. I want to be able to select areas that are blurry. The most interesting is the motion blur.
For example: I made a photo of moving coin and want to detect blurred areas from left and right
Another one:
I tried several methods and the gradient search turned out to be the best. Here the result:
But this method is absolutely not suitable for a non-uniform background. And I can't find blurred areas on photo with car
used code:
import cv2
import numpy as np
import blure as bl
def put_mask(image, mask):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return cv2.filter2D(src=gray, ddepth=-1, kernel=mask)
width, height, x, y = 550, 400, 50, 100
img = cv2.imread("car.jpg")
image = img[y:y+height, x:x+width]
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
mask_1 = np.array([ [1, 0, -1],
[2, 0, -2],
[1, 0, -1]])
mask_2 = np.array([ [1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])
masked_1 = cv2.filter2D(gray, ddepth=-1, kernel=mask_1)
masked_2 = cv2.filter2D(gray, ddepth=-1, kernel=mask_2)
masked = cv2.bitwise_or(masked_1, masked_2)
cv2.imshow("edges", image)
cv2.imshow("grad", masked)
cv2.waitKey(0)
cv2.destroyAllWindows()
Related
I have tried to segment cells in H&E-stained histopathological images using Watershed algorithm of opencv-python.
The code I used is totally same as Docs opencv code in link below.
Watershed Code Source
But as you see the result, the performance of segmentation is not that much good.
Some cells could not be detected.
I want to detect all of cells at a time in that image.
In the case of cell in biomedical, I think this is more sensitive than normal object segmentation.
In original code, I added and applied two Blur algorithms before using cv2.morphologyEx().
img = cv2.imread("Path_of_Image")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Convert to Binary Image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.5*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
markers = cv2.watershed(img_rgb, markers)
img_rgb[markers == -1] = [255, 0, 0]
images = [gray, thresh, sure_bg, dist_transform, sure_fg, unknown, markers, img_rgb]
titles = ['Gray','Binary','Sure BG','Distance','Sure FG','Unknow','Markers','Result']
plt.figure(figsize=(12, 12))
for i in range(len(images)):
plt.subplot(2, 4, i + 1),
plt.imshow(images[i], cmap='gray'),
plt.title(titles[i]),
plt.xticks([]),plt.yticks([])
# plt.figure(figsize= (5, 5))
# plt.tight_layout()
plt.show()
There was a litte bit improvement, but still need changes.
How can I deal with this problem? Do I have to more examine Marker value or something?
I wonder your thinking.
Thank you in advance.
[Add]
This is Original Image.
Original Image
I have an image something like the image below (on the left):
I want to extract only the pixels in red on the right: the pixels that belong to a 1px vertical line, but not to any thicker line or other region with more than 1 adjacent black pixel. The image is bitonal.
I have so far tried a morphology OPEN with a vertical (10px, which is find for my purposes) and horizontal kernel and taken the difference, but this needs an awkward shift and leaves some "speckles":
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 10))
vertical_mask1 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel,
iterations=1)
horz_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 1))
horz_mask = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horz_kernel,
iterations=1)
M = np.float32([[1,0,-1],[0,1,1]])
rows, cols = horz_mask.shape
vertical_mask = cv2.warpAffine(horz_mask, M, (cols, rows))
result = cv2.bitwise_and(thresh, cv2.bitwise_not(horz_mask))
What is the correct way to isolate the 1px lines (and only the 1px lines)?
In the general case, for other kernels, this question is: how do I find all pixels in the image that are in regions that the kernel "fits inside" (and then a subtraction to get my desired result)?
That's basically (binary) template matching. You need to derive proper templates from your "kernels". For larger "kernels", that might involve using masks for these templates, too, cf. cv2.matchTemplate.
What's the most important feature for a single pixel vertical line? The left and right neighbour of the current pixel must be 0. So, the template to match is [0, 1, 0]. By using the TemplateMatchMode cv2.TM_SQDIFF_NORMED, perfect matches will lead to close to 0 values in the result array.
You can mask those locations, and dilate according to the size of your template. Then, you use bitwise_and to extract the actual pixels that belong to your template.
Here's some code with a few template ("kernels"):
import cv2
import numpy as np
img = cv2.imread('AapJk.png', cv2.IMREAD_GRAYSCALE)[:, :50]
vert_line = np.array([[0, 1, 0]], np.uint8)
cross = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8)
corner = np.array([[0, 0, 1], [0, 0, 1], [1, 1, 1]], np.uint8)
for i_k, k in enumerate([vert_line, cross, corner]):
m, n = k.shape
img_tmp = 1 - img // 255
mask = cv2.matchTemplate(img_tmp, k, cv2.TM_SQDIFF_NORMED) < 10e-6
mask = cv2.dilate(mask.astype(np.uint8), np.ones((m, n)), anchor=(n-1, m-1))
m, n = mask.shape
mask = cv2.bitwise_and(img_tmp[:m, :n], mask)
out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
roi = out[:m, :n]
roi[mask.astype(bool), :] = [0, 0, 255]
cv2.imwrite('{}.png'.format(i_k), out)
Vertical line:
Cross:
Bottom right corner 3 x 3:
Larger templates ("kernels") most likely will require additional masks, depending on how many or which neighbouring pixels should be considered or not.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.19041-SP0
Python: 3.9.1
PyCharm: 2021.1.3
NumPy: 1.20.3
OpenCV: 4.5.2
----------------------------------------
I tried these approaches but didn't get any real changes. actually, I am trying to build a handwritten OCR using Google cloud vision API. please suggest to me what can I do for preprocessing steps.
1.
image = cv2.fastNlMeansDenoisingColored(image, None, 10, 10, 7, 15)
kernel = np.ones((5, 5), np.uint8)
image = cv2.dilate(image, kernel, iterations = 1)
kernel = np.ones((5, 5), np.uint8)
image = cv2.erode(image, kernel, iterations = 1)
Another way is HSV color filter. Because you are using blue pen, so we can choice the color that we want. Sample code:
import cv2
import numpy as np
image = cv2.imread('9rS31.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_green = np.array([100, 43, 20])
upper_green = np.array([130, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
res = cv2.bitwise_and(image, image, mask=mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
ret, generator = cv2.threshold(gray, 1,255,cv2.THRESH_BINARY)
cv2.imwrite("img.jpg",generator)
Generated image:
The noise is including horizontal line in your text book. So one method is using
cv2.getStructuringElement
You can find more information on the internet. Sample code:
import cv2
# Load image
image = cv2.imread('9rS31.jpg')
img=image.copy()
# Remove border
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
result = cv2.add(temp2, image)
# Convert to grayscale and Otsu's threshold
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)
_,thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
cv2.imwrite('img.jpg',thresh)
cv2.imshow('img', thresh)
cv2.waitKey()
Generated image:
I am trying to find centroid of circular objects OR a circle that can bounding around circular objects in a grayscale image.
So far what I have done is turn that grayscale image to binary image using adaptive thresholding.
Grayscale image
Threshold image
Up till now, i have used hough transform and Findcontour. None of these method work.
What should be an approach to this?
I got a decent result using the Hough transform for circles. This is the pipeline:
img = cv2.imread('I7Ykpbs.jpg', 0)
img = cv2.GaussianBlur(img, (5, 5), 2, 2)
img_th = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 9, 3)
circles = cv2.HoughCircles(img_th, cv2.HOUGH_GRADIENT, 2, minDist=30,
param1=200, param2=40, minRadius=10, maxRadius=20)
for i in range(circles.shape[1]):
c = circles[0,i,:]
center = (np.round(c[0]), np.round(c[1]))
radius = np.round(c[2])
# print(center)
# print(radius)
if np.linalg.norm(np.array([600., 600.])-center) < 500.:
cv2.circle(img, center, 3, (0,255,0), -1, 8, 0)
cv2.circle(img, center, radius, (0,0,255), 3, 8, 0)
plt.imshow(img)
plt.show()
It's not perfect but I think you can start from here and do some finetuning on parameters and preprocessing to optimize the result.
How to fill OpenCV image with one solid color?
Using the OpenCV C API with IplImage* img:
Use cvSet(): cvSet(img, CV_RGB(redVal,greenVal,blueVal));
Using the OpenCV C++ API with cv::Mat img, then use either:
cv::Mat::operator=(const Scalar& s) as in:
img = cv::Scalar(redVal,greenVal,blueVal);
or the more general, mask supporting, cv::Mat::setTo():
img.setTo(cv::Scalar(redVal,greenVal,blueVal));
Here's how to do with cv2 in Python:
# Create a blank 300x300 black image
image = np.zeros((300, 300, 3), np.uint8)
# Fill image with red color(set each pixel to red)
image[:] = (0, 0, 255)
Here's more complete example how to create new blank image filled with a certain RGB color
import cv2
import numpy as np
def create_blank(width, height, rgb_color=(0, 0, 0)):
"""Create new image(numpy array) filled with certain color in RGB"""
# Create black blank image
image = np.zeros((height, width, 3), np.uint8)
# Since OpenCV uses BGR, convert the color first
color = tuple(reversed(rgb_color))
# Fill image with color
image[:] = color
return image
# Create new blank 300x300 red image
width, height = 300, 300
red = (255, 0, 0)
image = create_blank(width, height, rgb_color=red)
cv2.imwrite('red.jpg', image)
Create a new 640x480 image and fill it with purple (red+blue):
cv::Mat mat(480, 640, CV_8UC3, cv::Scalar(255,0,255));
Note:
height before width
type CV_8UC3 means 8-bit unsigned int, 3 channels
colour format is BGR
The simplest is using the OpenCV Mat class:
img=cv::Scalar(blue_value, green_value, red_value);
where img was defined as a cv::Mat.
Use numpy.full. Here's a Python that creates a gray, blue, green and red image and shows in a 2x2 grid.
import cv2
import numpy as np
gray_img = np.full((100, 100, 3), 127, np.uint8)
blue_img = np.full((100, 100, 3), 0, np.uint8)
green_img = np.full((100, 100, 3), 0, np.uint8)
red_img = np.full((100, 100, 3), 0, np.uint8)
full_layer = np.full((100, 100), 255, np.uint8)
# OpenCV goes in blue, green, red order
blue_img[:, :, 0] = full_layer
green_img[:, :, 1] = full_layer
red_img[:, :, 2] = full_layer
cv2.imshow('2x2_grid', np.vstack([
np.hstack([gray_img, blue_img]),
np.hstack([green_img, red_img])
]))
cv2.waitKey(0)
cv2.destroyWindow('2x2_grid')
For an 8-bit (CV_8U) OpenCV image, the syntax is:
Mat img(Mat(nHeight, nWidth, CV_8U);
img = cv::Scalar(50); // or the desired uint8_t value from 0-255
color=(200, 100, 255) # sample of a color
img = np.full((100, 100, 3), color, np.uint8)
If you are using Java for OpenCV, then you can use the following code.
Mat img = src.clone(); //Clone from the original image
img.setTo(new Scalar(255,255,255)); //This sets the whole image to white, it is R,G,B value
I personally made this python code to change the color of a whole image opened or created with openCV . I am sorry if it's not good enough , I am beginner 😚😚 .
def OpenCvImgColorChanger(img,blue = 0,green = 0,red = 0):
line = 1
ImgColumn = int(img.shape[0])-2
ImgRaw = int(img.shape[1])-2
for j in range(ImgColumn):
for i in range(ImgRaw):
if i == ImgRaw-1:
line +=1
img[line][i][2] = int(red)
img[line][i][1] = int(green)
img[line][i][0] = int(blue)