Reputation: 41
I am trying to clear out the grids so that I can use the plot alone in a different process. I am trying to solve it using opencv. I have both actual and inverted image. I am not expert in python. Any help could be great.
Thanks in advance
Actual image
inverted image
Upvotes: 4
Views: 2453
Reputation: 53081
Here is a pretty simple solution using Imagemagick. But the same concepts can be use from OpenCV. Sorry, I am not fluent with OpenCV.
Threshold the image
Perform morphologic close
Use connected components processing to remove extraneous features
Input:
kernel="5x5: 0,0,0,0,0 1,1,1,1,1 1,1,1,1,1 1,1,1,1,1 0,0,0,0,0"
convert img.png -threshold 75% \
-morphology close "$kernel" \
-define connected-components:area-threshold=100 \
-define connected-components:mean-color=true \
-connected-components 4 result.png
ADDITION:
Here is Python Wand code to do the same thing. Python Wand is based upon Imagemagick. It will require Wand 0.5.6 (when available) and Imagemagick 7.
#!/bin/python3.7
from wand.image import Image
with Image(filename='curve.png') as img:
krnl="5x5: 0,0,0,0,0 1,1,1,1,1 1,1,1,1,1 1,1,1,1,1 0,0,0,0,0"
img.threshold(threshold=0.75)
img.morphology(method='close',kernel=krnl)
img.connected_components(connectivity=4, area_threshold=100, mean_color=True)
img.save(filename='curve_proc.png')
Upvotes: 2
Reputation: 46600
Here's an approach that uses a combination of filtering techniques and masks.
Here's the result
import cv2
import numpy as np
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 15)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,3)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
erode = cv2.erode(thresh, kernel, iterations=1)
dilate = cv2.dilate(erode, kernel, iterations=3)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
mask = np.zeros(image.shape, dtype=np.uint8)
for c in cnts:
area = cv2.contourArea(c)
if area > 850:
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
mask = cv2.dilate(mask, kernel, iterations=1)
image = 255 - image
result = 255 - cv2.bitwise_and(mask, image)
cv2.imshow('result', result)
cv2.waitKey(0)
2nd Approach
Here's an alternative approach which is the same as the 1st approach but uses specialized horizontal and vertical kernels for filtering instead. This approach is probably more robust. Instead of using guess and check morphological transformations, we have dedicated kernels that filter out the horizontal/vertical grid lines.
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,5))
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,1))
Here's the mask result after going through each kernel
The result is pretty much the same but slightly cleaner :)
import cv2
import numpy as np
image = cv2.imread('1.png',0)
blur = cv2.GaussianBlur(image, (5,5), 0)
thresh = cv2.threshold(blur, 130, 255, cv2.THRESH_BINARY_INV)[1]
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,5))
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,1))
remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel)
remove_vertical = cv2.morphologyEx(remove_horizontal, cv2.MORPH_OPEN, horizontal_kernel)
cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
mask = np.ones(image.shape, dtype=np.uint8)
for c in cnts:
area = cv2.contourArea(c)
if area > 50:
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.dilate(mask, kernel, iterations=1)
image = 255 - image
result = 255 - cv2.bitwise_and(mask, image)
cv2.imshow('result', result)
cv2.imwrite('result.png', result)
cv2.imshow('mask', mask)
cv2.waitKey(0)
Upvotes: 2
Reputation: 436
You can use the opening or closing of your image (depending if you are using the normal or inverted image). Opening will first erode your image and then dilate it. This will remove small/thin objects assuming bright objects over black background.
For example, in the case of your inverted image, use
out = cv2.morphologyEx(src, MORPH_OPEN)
For more information check out this tutorial
Upvotes: 2