2

I am using OpenCV 4 and latest Python version. Got all the packages aswell.

I know how to resize, grayscale, blur, edge etc, but I get so many errors, seems like I cant get any detection.

Here is the Multimeter display image which is cropped which I am trying to detect and extract the digits from.

I need a simple code or help to code and to retrieve the digits, tried multiple guides without success. OpenCV is new to me, but took me 2-3 days to learn the basic image processing capabilities.

Digital multimeter non color

Ok, Now I have updated the code. I want to extract the digits from the warped and transformed binary image. But I get either errors or I need to delete parts of the code in order to at least show me the two images. Here is the code so far:

# 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.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, (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("Multimeter2", thresh)


cv2.waitKey(0)
cv2.destroyAllWindows()

Warped,Transformed, tresholded

Edde87
  • 59
  • 1
  • 3
  • Please provide samples of the code you have tried - that will make it easier for people to respond to your question. – Eric Broda Oct 24 '19 at 19:39

2 Answers2

0

You can use cv2.adaptiveThreshold() to get a binary image then extract the display by sorting for the largest contour. Once you have detected this contour, you can then apply your perspective transformation

enter image description here

import cv2

image = cv2.imread('1.jpg')
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)

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
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.drawContours(image, [c], -1, (36,255,12), 3)
    # cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 1)
    rect = c
    break

cv2.imshow('image', image)
cv2.waitKey()
nathancy
  • 42,661
  • 14
  • 115
  • 137
  • Ok, super thanks for your help nathanacy, so now I have found the contours and performed a perspective transform. How do I proceed? Need to treshold again, make contours where the actual digits and extract them? – Edde87 Oct 25 '19 at 00:33
  • After perspective transforming, I would threshold again then perform morphological operations to extract each digit – nathancy Oct 25 '19 at 00:42
  • 1
    Don't edit answers as an attempt to reply. Use the comment section or edit your own post – Tim Stack Oct 25 '19 at 12:20
  • As you see from my above and updated code. I need help to actually detect the digits now, that means draw a bounding box,then extract them and print out the detected digits to an image or to console. – Edde87 Oct 25 '19 at 13:21
0

I struggle to write a correct code for that, still in learning process...

I took that morphed image and made another python script to simplify things. Now lets say the image is already binary, transformed and warped. How can I detect the digits and display the information on the image or on console after extraction? I have not learned to do that yet. I struggle to find the coordinates of the digits, I just found the rectangle boundry of the image it self but not what I am looking for.

In other words: I need help to find the boundry boxes first of the digits, detect and extract them.

Image example

Here is simplified sample code so far:

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

image = cv2.imread("Morph.jpg")
copy = image.copy()
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cnts = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

ROI_number = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
cv2.rectangle(copy,(x,y),(x+w,y+h),(36,255,12),2)
ROI_number += 1



cv2.imshow('thresh', image)
cv2.imshow('copy', copy)
cv2.imwrite("Morphed_rectangle.jpg",copy)

cv2.waitKey(0)
cv2.destroyAllWindows()
Edde87
  • 59
  • 1
  • 3
  • So, how do I extract the digits from the binary image and code above? Anyone has any tips? I use the latest OpenCV and python – Edde87 Oct 27 '19 at 11:46