Extracting digits from image with python and OpenCV

独自空忆成欢 提交于 2021-01-28 18:10:36

问题


I am looking for some coding solution/help to extract the digits from the LCD display and then output the value from the image.

Below is the code and example images and how I got so far, but I need some further help to actually extract the "digits" from the image and output the value.

I have made digits lookup table from an earlier example,

# import the necessary packages
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2

# define the dictionary of digit segments so we can identify
# each digit on the thermostat
DIGITS_LOOKUP = {
(1, 1, 1, 0, 1, 1, 1): 0,
(0, 0, 1, 0, 0, 1, 0): 1,
(1, 0, 1, 1, 1, 1, 0): 2,
(1, 0, 1, 1, 0, 1, 1): 3,
(0, 1, 1, 1, 0, 1, 0): 4,
(1, 1, 0, 1, 0, 1, 1): 5,
(1, 1, 0, 1, 1, 1, 1): 6,
(1, 0, 1, 0, 0, 1, 0): 7,
(1, 1, 1, 1, 1, 1, 1): 8,
(1, 1, 1, 1, 0, 1, 1): 9}

# load the example image
image = cv2.imread("Multimeter_1.jpg")

# pre-process the image by converting it to
# graycale, blurring it, and computing an edge map
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,87,9)


# find contours in the edge map,
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

rect = None
# loop over the contours
for c in cnts:
# approximate the contour
x,y,w,h = cv2.boundingRect(c)
#cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 1)
cv2.drawContours(image, [c], -1, (36,255,12),3)
rect = c

peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)

if len(approx) == 4:
    rect = approx
    break


# extract the display, apply a perspective transform

warped = four_point_transform(thresh, rect.reshape(4, 2))
output = four_point_transform(image, rect.reshape(4, 2))

# Warp the image and perform morphology to clean it

thresh = cv2.threshold(warped, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)


# pre-process the image by converting it to
# graycale, blurring it, and computing an edge map
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,87,9)


# find contours in the edge map,
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

rect = None
# loop over the contours
for c in cnts:
# approximate the contour
x,y,w,h = cv2.boundingRect(c)
#cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 1)
cv2.drawContours(image, [c], -1, (36,255,12),3)
rect = c

peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.05 * peri, True)

if len(approx) == 4:
    rect = approx
    break


# extract the display, apply a perspective transform

warped = four_point_transform(thresh, rect.reshape(4, 2))
output = four_point_transform(image, rect.reshape(4, 2))
# Warp the image and perform morphology to clean it

thresh = cv2.threshold(warped, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

cnts = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
digitCnts = []

# loop over the digit area candidates
for c in cnts:
(x,y,w,h) = cv2.boundingRect(c)

# if the contour is sufficiently large, it must be a digit
if w >= 25 and (h >= 50 and h <= 60):
    digitCnts.append(c)





cv2.imshow("Multimeter", image)
cv2.imshow("Threshed", thresh)
cv2.imwrite("Threshed.jpg",thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

Can someone very profiecient in python, especially in Open CV help me out with this. This is a school assignment about the image process part and I have decided to use Python and OpenCV, so it is not a programming assignment and the code will be used just to do and explain the actual image processing nothing less or more. I just need help to actually extract the digits out of the treshed image. I also provided the original image from the LCD display in case there is a better method to achieve what I am looking for.


回答1:


Here's an approach using the thresholded input image you have provided

  • Convert image to grayscale and Otsu's threshold
  • Perform morph close with a horizontal kernel to merge the numbers into a single contour
  • Find contours and filter using a minimum threshold area to filter out the large outer contour
  • Sort by largest contour area which should be the desired text contour
  • Iterate through contours and extract ROI using Numpy slicing

Starting from your input image

We morph close using a horizontal kernel to merge the numbers together into a single contour

From here we find contours and filter to only keep contours that are below a threshold area. Specifically, we use 0.75 * w * h to filter out the outer contours. Once we do this, the desired text contour should be the largest contour

Finally we extract the ROI using cv2.boundingRect() and Numpy slicing

import cv2

image = cv2.imread('1.jpg')
original = image.copy()
h, w, _ = image.shape

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

cnts = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
minimum_area = .75 * h * w
cnts = [c for c in cnts if cv2.contourArea(c) < minimum_area]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    ROI = 255 - original[y:y+h, x:x+w]
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    break

cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()


来源:https://stackoverflow.com/questions/58663227/extracting-digits-from-image-with-python-and-opencv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!