Match ROI or shape in several images for analysis - python

I have a lot of images to use. But this question I am going to just use the first and last image.
Image 1 of 83
Image 83 of 83
I ran Image 1 through this code
import numpy as np
import cv2
def process(filename, key):
gwash = cv2.imread(filename)
gwashBW = cv2.cvtColor(gwash, cv2.COLOR_BGR2GRAY)
ret,thresh1 = cv2.threshold(gwashBW,179,255,cv2.THRESH_BINARY)
kernel = np.ones((1,1),np.uint8)
erosion = cv2.erode(thresh1, kernel,iterations = 1)
opening = cv2.morphologyEx(erosion, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
_, contours ,_ = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
idx = np.argmax(areas)
cnt = contours[idx]
mask = np.zeros_like(gwash)
cv2.drawContours(mask, contours, idx, (255,255,255), -1)
out = np.zeros_like(gwash)
out[mask == 255] = gwash[mask == 255]
cv2.imwrite('img/out{}.jpg'.format(key),out)
print idx
This one result I have gotten better and worst results.
Here is the contour code I used and result
import cv2
import numpy as np
import imutils
from matplotlib import pyplot as plt
def process(filename, key):
image = cv2.imread(filename)
resized = imutils.resize(image, width=600)
ratio = image.shape[0] / float(resized.shape[0])
blurred = cv2.GaussianBlur(resized, (5, 5), 0)
gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)
lab = cv2.cvtColor(resized, cv2.COLOR_BGR2LAB)
thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY)[1]
imagem = cv2.bitwise_not(thresh)
th4 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
th3 = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
gray_2 = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
gray_blur = cv2.GaussianBlur(gray, (15, 15), 0)
thresh_2 = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 11, 1)
kernel = np.ones((1, 1), np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=500)
cnts = cv2.findContours(closing.copy(), cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnts2 = cv2.findContours(closing.copy(), cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
cnts2 = cnts2[0] if imutils.is_cv2() else cnts2[1]
# loop over the contours
for c in cnts:
# compute the center of the contour
M = cv2.moments(c)
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
# multiply the contour (x, y)-coordinates by the resize ratio,
# then draw the contours and the name of the shape and labeled
# color on the image
c = c.astype("float")
c *= ratio
c = c.astype("int")
cX *= ratio
cY *= ratio
cv2.drawContours(image, [c], -1, (0, 255, 0), 5)
cv2.circle(image, (int(cX),int(cY)),5,300,3)
#r = 100.0 / image.shape[1]
#dim = (100, int(image.shape[0] *r))
#imageresized = cv2.resize(image,(2048,2048),dim,interpolation = cv2.INTER_AREA)
cv2.imwrite( 'i/image_{}.jpg'.format(key) ,QR_final )
print 'image_{}.jpg'.format(key)
So my question is what would the best approach be to accurately find the canvas shape in all the photos using python ?

Related

Line detection from a picture

picture to be detected - different color
For a picture like above, the lines are blue, I use mask to get the contours of these lines, please see below code:
img = cv2.imread("./more5.png")#"https://i.stack.imgur.com/LiLPv.png"
blueLower = np.array([50,50,50])
blueUpper = np.array([130,255,255])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
blue_mask = cv2.inRange(hsv, blueLower, blueUpper)
blue = cv2.bitwise_and(img ,img ,mask=blue_mask)
contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
Lines detected
complete code:
import numpy as np
import cv2
def preprocess(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
img_canny = cv2.Canny(img_blur, 50, 50) # edge cascade
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
# BGR to HSV to LAB to ...
def find_tip(points, convex_hull):
length = len(points)
indices = np.setdiff1d(range(length), convex_hull)
for i in range(2):
j = indices[i] + 2
if j > length - 1:
j = length - j
if np.all(points[j] == points[indices[i - 1] - 2]):
return tuple(points[j])
img = cv2.imread("./more5.png")
blueLower = np.array([50,50,50])
blueUpper = np.array([130,255,255])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
blue_mask = cv2.inRange(hsv, blueLower, blueUpper)
blue = cv2.bitwise_and(img ,img ,mask=blue_mask)
contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
print(f"Contours size {len(contours)}") #
for cnt in contours:
peri = cv2.arcLength(cnt, True) #
approx = cv2.approxPolyDP(cnt, 0.004 * peri, True) #
hull = cv2.convexHull(approx, returnPoints=False)
sides = len(hull) #
if 6 > sides > 3 and sides + 2 == len(approx):
arrow_tip = find_tip(approx[:,0,:], hull.squeeze())
if arrow_tip:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 3)
cv2.circle(img, arrow_tip, 3, (0, 0, 255), cv2.FILLED)
cv2.imshow("Image", img)
cv2.waitKey(0)
However, if the line and the connected shape is the SAME color (please see the picture below), this method does NOT work anymore, how can I detect the lines from such a picture? Thanks for any ideas!
picture to be detected - same color
If your graph is a tree (it does not has closed circuits), then only the lines are connected to the same area on both sides.
If you paint the external area of the same color, only the lines will have the same color on both sides
Then you can do a convolution to have the lines averaged with the external space color, and the other lines averaged with the internal spaces color
import matplotlib.pyplot as plt
import numpy as np
#download the example image from this webpage
from PIL import Image as Pim
from io import BytesIO
import requests
photoURL="https://i.stack.imgur.com/LiLPv.png"
response = requests.get(photoURL)
image = np.array(Pim.open(BytesIO(response.content)).convert('L')) # Convert to greyscale
#mask to only 2 colors
gray=128
black=0
Monochrome = lambda t: gray if t!=image[0,0] else black #If color<>upper left color, then it is 0, else is 1
vfunc = np.vectorize(Monochrome)
image=vfunc(image)
#fill the external space with the same color as the upper left pixel
import cv2
UpperLeftPixel=(0,0)
AdjacentColor=255#White
imajeAdjacent=cv2.floodFill(image, None, UpperLeftPixel, AdjacentColor)
#convolution to average colors of lines with neighbor spaces
averagingFilter=np.ones(shape=(9,9))/9**2
import scipy
from scipy.signal import convolve2d as conv2d
image=conv2d(image,averagingFilter, mode="same")
plt.imshow(image)
plt.show()

How can i find these containers on photo by opencv

there's an image
it's my code
from cv2 import cv2
import numpy as np
image = cv2.imread('Photos\\1photo.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
kernel_size = 5
blur = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)
sharp_strength = 9.1
sharpen_kernel = np.array([[-1, -1, -1],
[-1, sharp_strength, -1],
[-1, -1, -1]])
sharpen = cv2.filter2D(gray, -1, sharpen_kernel)
cv2.imshow('sharpen', sharpen)
cv2.waitKey()
threshold = 140
max_value = 280
thresh = cv2.threshold(sharpen, threshold, max_value, cv2.THRESH_BINARY_INV)[1]
thresh = cv2.bitwise_not(thresh)
cv2.imshow("ThreshInv", thresh)
cv2.waitKey()
kernel_size = 3
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
cv2.imshow("Close", closing)
cv2.waitKey()
#
cnts = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
min_area = 80
max_area = 150
image_number = 0
for c in cnts:
area = cv2.contourArea(c)
if min_area < area < max_area:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36, 255, 12), 2)
cv2.imshow('image', image)
cv2.waitKey()
After blur, thresh, inversion and morph, i have image like this
Carriages and containers are quite visible, but findContours can't detect them.
Can i fix this?

easyocr detects no integer values

I'm trying to detects the numbers found in my sqares, and I thought I could use the libary easyocr, but for some reason I read the wrong values.
This is the console output:
And here I have all my pictures (they are seperated, this is just to show them all)
¨
How can it be that i don't find any numbers?
from PIL import Image
from operator import itemgetter
import numpy as np
import easyocr
import cv2
import re
import imutils
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract'
reader = easyocr.Reader(['ch_sim','en']) # need to run only once to load model into memory
#Define empty array
Cubes = []
def getNumber(ROI):
img = cv2.imread(ROI)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
#cv2.imshow(thresh)
#cv2.imshow('Thresholded original',thresh)
#cv2.waitKey(0)
## Get contours
contours,h = cv2.findContours(thresh,cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
## only draw contour that have big areas
imx = img.shape[0]
imy = img.shape[1]
lp_area = (imx * imy) / 10
tmp_img = img.copy()
for cnt in contours:
approx = cv2.approxPolyDP(cnt,0.01 * cv2.arcLength(cnt, True), True)
if cv2.contourArea(cnt) > lp_area:
# Draw box corners and minimum area rectangle
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
#cv2.drawContours(tmp_img, [box], 0, (0, 50, 255), 3)
#cv2.circle(tmp_img, tuple(box[0]), 8, (0, 255, 0), -1)
#cv2.circle(tmp_img, tuple(box[1]), 8, (0, 255, 0), -1)
#cv2.circle(tmp_img, tuple(box[2]), 8, (0, 255, 0), -1)
#cv2.circle(tmp_img, tuple(box[3]), 8, (0, 255, 0), -1)
#cv2.imshow(tmp_img)
#cv2.imshow('Minimum Area Rectangle', tmp_img)
#cv2.waitKey(0)
## Correct orientation and crop
# Link, https://jdhao.github.io/2019/02/23/crop_rotated_rectangle_opencv/
width = int(rect[1][0])
height = int(rect[1][1])
src_pts = box.astype("float32")
dst_pts = np.array([[0, height-1],
[0, 0],
[width-1, 0],
[width-1, height-1]], dtype="float32")
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warped = cv2.warpPerspective(img, M, (width, height))
# Run OCR on cropped image
# If the predicted value is digit print else rotate first
result = reader.readtext(warped)
print(result)
predicted_digit = result[0][1]
if np.char.isdigit(predicted_digit) == True:
cv2.imshow("warped " + ROI,warped)
else:
rot_img = warped.copy()
for i in range(0, 3):
rotated_image = cv2.rotate(rot_img, cv2.cv2.ROTATE_90_CLOCKWISE)
result = reader.readtext(rotated_image)
#if np.array(result).size == 0:
# continue
if not result:
rot_img = rotated_image
continue
#if len(result) == 0:
# continue
predicted_digit = result[0][1]
#print(result)
#print(predicted_digit)
#cv2.imshow(rotated_image)
if np.char.isdigit(predicted_digit) == True:
cv2.imshow("Image " + ROI, rotated_image)
break
rot_img = rotated_image
return predicted_digit
def sortNumbers(Cubes):
Cubes = sorted(Cubes, key=lambda x: int(x[2]))
#Cubes.sort(key=itemgetter(2)) # In-place sorting
#Cubes = sorted(Cubes, key=itemgetter(2)) # Create a new list
return Cubes
#img = cv2.imread('gulRecNum.jpg')
img = cv2.imread('boxes.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# convert to HSV, since red and yellow are the lowest hue colors and come before green
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# create a binary thresholded image on hue between red and yellow
#Change these if cube colours changes?
lower =(20, 100, 100)
upper = (30, 255, 255)
#lower = (0,240,160)
#upper = (30,255,255)
thresh = cv2.inRange(hsv, lower, upper)
# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9))
clean = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15,15))
clean = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# get external contours
contours = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
result2 = img.copy()
mask = np.zeros(result2.shape, dtype=np.uint8)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
ROI_number = 0
for c in contours:
cv2.drawContours(result2,[c],0,(0,0,0),2)
# get rotated rectangle from contour
rot_rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rot_rect)
box = np.int0(box)
# draw rotated rectangle on copy of img
cv2.drawContours(result2,[box],0,(0,0,0),2)
# Gør noget hvis arealet er større end 1.
# Whats the area of the component?
areal = cv2.contourArea(c)
if(areal > 1):
# get the center of mass
M = cv2.moments(c)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
center = (cx, cy)
print("\nx: ",cx,"\ny: ",cy)
color = (0, 0, 255)
cv2.circle(result2, center, 3, color, -1)
cv2.putText(result2, "center", (int(cx) - 10, int(cy) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 1.2, color, 2)
x,y,w,h = cv2.boundingRect(c)
ROI = 255 - thresh[y:y+h, x:x+w]
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
#Read saved image (number)
result = getNumber('ROI_{}.png'.format(ROI_number))
print("ROI_number: ", result)
Cubes.append([cx, cy, result])
ROI_number += 1
# save result
cv2.imwrite("4cubes_result2.png",result2)
# display result
imS = cv2.resize(result2, (600, 400))
cv2.imshow("result2", imS)
#cv2.imshow('mask', mask)
#cv2.imshow('thresh', thresh)
SortedCubes = sortNumbers(Cubes)
print("\nFound array [x, y, Cube_num] = ", Cubes)
print("Sorted array [x, y, Cube_num] = ", SortedCubes)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT
I also got these two pictures to try with
EDIT 2
y: 160
shape: rectangle
areal: 723.0
['ta'] : image should have been 4
x: 269
y: 155
shape: rectangle
areal: 637.5
['1'] : image should have been 1
x: 64
y: 149
shape: rectangle
areal: 748.5
['20'] : image should have been 2
x: 125
y: 141
shape: rectangle
areal: 714.5
['5.'] : image should have been 5
x: 222
y: 127
shape: rectangle
areal: 662.5
['3'] : image should have been 3
x: 165
y: 101
shape: rectangle
areal: 666.5
['40'] : image should have been 7
x: 58
y: 96
shape: rectangle
areal: 782.5
['L', 'RJ'] : image should have been 8
x: 279
y: 90
shape: rectangle
areal: 653.5
['EJ'] : image should have been 9
x: 107
y: 84
shape: rectangle
areal: 717.5
['C'] : image should have been 6
All the images is cut from this image
You may need a different processing method and you may need to set the page-segmentation-mode (psm) for the tesseract
Here, when you apply adaptive-thresholding (at) with bitwise_notoperation
Now, when you read the image with psm mode 6 (Assume a single uniform block of text.)
Result will be:
['34', '215', '28', '7', '5']
Unfortunately 6 and 9 are not detected, maybe if you change the at parameters you can find a better result.
Code:
import cv2
import pytesseract
img = cv2.imread("u3ZTw.png")
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.adaptiveThreshold(gry, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY_INV, 59, 88)
bnt = cv2.bitwise_not(thr)
txt = pytesseract.image_to_string(bnt, config="--psm 6 digits")
txt = txt.strip().split("\n")
print(txt)
cv2.imshow("bnt", bnt)
cv2.waitKey(0)
For photos in the Edit:
You must change the adaptive-threshold parameters for each different image.
To be more specific, you must change the blockSize and C params to get the expected result.
For instance for number 4 and 5, I changed the:
blockSize: 31 (previously 59)
C: 30 (previously 88)
import cv2
import pytesseract
img = cv2.imread("num5.png")
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.adaptiveThreshold(gry, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY_INV, 31, 30)
bnt = cv2.bitwise_not(thr)
txt = pytesseract.image_to_string(bnt, config="--psm 6 digits")
txt = txt.strip().split("\n")
print(txt)
cv2.imshow("bnt", bnt)
cv2.waitKey(0)
Images:
Result:
['4']
['5']

How to extract oval contours from an image and save into different variables?

I need to extract the 12 oval shapes from the image and store them in separate variables say 1 to 12.
The original image was as follows
Original Image:
Output image:
Can someone help me extract all those oval shapes into different variables ?
my code is
import cv2
import numpy as np
path = r'/home/parallels/Desktop/Opencv/data/test.JPG'
i = cv2.imread(path, -1)
img_rgb = cv2.resize(i, (1280,720))
cv2.namedWindow("Original Image",cv2.WINDOW_NORMAL)
img = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
img = cv2.bilateralFilter(img,9,105,105)
r,g,b=cv2.split(img)
equalize1= cv2.equalizeHist(r)
equalize2= cv2.equalizeHist(g)
equalize3= cv2.equalizeHist(b)
equalize=cv2.merge((r,g,b))
equalize = cv2.cvtColor(equalize,cv2.COLOR_RGB2GRAY)
ret,thresh_image = cv2.threshold(equalize,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY)
equalize= cv2.equalizeHist(thresh_image)
canny_image = cv2.Canny(equalize,250,255)
canny_image = cv2.convertScaleAbs(canny_image)
kernel = np.ones((3,3), np.uint8)
dilated_image = cv2.dilate(canny_image,kernel,iterations=1)
contours, hierarchy = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10]
c=contours[0]
print(cv2.contourArea(c))
final = cv2.drawContours(img, [c], -1, (255,0, 0), 3)
mask = np.zeros(img_rgb.shape,np.uint8)
new_image = cv2.drawContours(mask,[c],0,255,-1,)
new_image = cv2.bitwise_and(img_rgb, img_rgb, mask=equalize)
cv2.namedWindow("new",cv2.WINDOW_NORMAL)
cv2.imshow("new",new_image)
cv2.waitKey(0)
You're on the right track. After obtaining your binary image, you can perform contour area + aspect ratio filtering. We can sort the contours in order from left-to-right using imutils.contours.sort_contours(). We find contours then filter using cv2.contourArea
and aspect ratio with cv2.approxPolyDP + cv2.arcLength. If they pass this filter, we draw the contours and append it to a oval list to keep track of the contours. Here's the results:
Filtered mask
Results
Isolated ovals
Output from oval list
Oval contours: 12
Code
import cv2
import numpy as np
from imutils import contours
# Load image, resize, convert to HSV, bilaterial filter
image = cv2.imread('1.jpg')
resize = cv2.resize(image, (1280,720))
original = resize.copy()
mask = np.zeros(resize.shape[:2], dtype=np.uint8)
hsv = cv2.cvtColor(resize, cv2.COLOR_RGB2HSV)
hsv = cv2.bilateralFilter(hsv,9,105,105)
# Split into channels and equalize
r,g,b=cv2.split(hsv)
equalize1 = cv2.equalizeHist(r)
equalize2 = cv2.equalizeHist(g)
equalize3 = cv2.equalizeHist(b)
equalize = cv2.merge((r,g,b))
equalize = cv2.cvtColor(equalize,cv2.COLOR_RGB2GRAY)
# Blur and threshold for binary image
blur = cv2.GaussianBlur(equalize, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Find contours, sort from left-to-right
# Filter using contour area and aspect ratio filtering
ovals = []
num = 0
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
for c in cnts:
area = cv2.contourArea(c)
x,y,w,h = cv2.boundingRect(c)
ar = w / float(h)
if area > 1000 and ar < .8:
cv2.drawContours(resize, [c], -1, (36,255,12), 3)
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
cv2.putText(resize, str(num), (x,y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (36,55,12), 2)
ovals.append(c)
num += 1
result = cv2.bitwise_and(original, original, mask=mask)
result[mask==0] = (255,255,255)
print('Oval contours: {}'.format(len(ovals)))
cv2.imshow('equalize', equalize)
cv2.imshow('thresh', thresh)
cv2.imshow('resize', resize)
cv2.imshow('result', result)
cv2.imshow('mask', mask)
cv2.waitKey()

Filtering noise from very noisy binary thresholded image

I would like to be able to analyze the following image, get the lines and find the average width.(My copy is much larger ~5K by ~4K) Cannot move to the next step due to all the noise after thresholding.
Using my code I was able to get to this point...
My issue is that it has a lot of noise in-between lines, which looks like noise that got condensed.
Here is my code...
image = np.copy(origImg)
newImage = np.empty_like(image)
scale = 64
height = image.shape[0]
width = image.shape[1]
dH = int(height / scale)
dW = int(width / scale)
xi = int(dH)
yi = int(dW)
fragments = []
image = cv2.bilateralFilter(image,9,75,75)
image = cv2.medianBlur(image, 21)
for i in range(0,height,dH):
for j in range(0,width,dW):
fragment = image[i:i + int(dH), j:j + int(dW)]
fragment = cv2.adaptiveThreshold(fragment, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 0)
fragments.append(fragment)
analyzed = com.stackArrayToImage(fragments)
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(analyzed, None, None, None, 8, cv2.CV_32S)
sizes = stats[1:, -1]
img2 = np.zeros((labels.shape), np.uint8)
for i in range(0, nlabels - 1):
if sizes[i] >= 100:
img2[labels == i + 1] = 255
analyzed = cv2.bitwise_not(img2)
analyzed = cv2.erode(analyzed, np.ones((5, 5)), iterations=2)
analyzed = cv2.dilate(analyzed, np.ones((5, 5), np.uint8))
dis.plotImages([origImg], "Origional")
dis.plotImages([analyzed], "Analyzed")
dis.displayStart()
Is there anyway I can remove that noise?
Thank you very much!
You can remove some of the noise using contour area filtering with cv2.contourArea. The idea is to filter using some threshold area. If a contour passes this filter then we can remove the noise by filling in the contour with cv2.drawContours. Using your binary image as input:
Detected contours to remove highlighted in green
Result
Depending on how much noise you want to remove, you can adjust the threshold area value
Code
import numpy as np
import cv2
# Load image, grayscale, Otsu's threshold
image = cv2.imread("1.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Find contours and filter using contour area
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 50:
cv2.drawContours(thresh, [c], -1, 0, -1)
cv2.drawContours(image, [c], -1, (36,255,12), -1)
result = 255 - thresh
cv2.imshow("image", image)
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey()

Categories