Ejemplo n.º 1
0
 def __init__(self, vlogger = None):
     self.vlogger = vlogger
     self.pre= None
     self.edged= None
     self.warp= ImageBlobWarping()
     self.p= Pool(processes = 6)
     self.bnight= False
Ejemplo n.º 2
0
 def __init__(self):
     self.vlogger = None
     self.pre= None
     self.edged= None
     self.warp= ImageBlobWarping()
     self.bnight= False
     self.ocr_engine = Ocr('spa', logger)
Ejemplo n.º 3
0
class PlateDetector(object):
    def __init__(self, vlogger = None):
        self.vlogger = vlogger
        self.pre = None
        self.edged = None
        self.warp = ImageBlobWarping()
        self.p  = Pool(processes = 6)


    def find(self, img):
        blobs = self.findBlobs(img)
        for b in blobs:
            plate = self.checkBlob(b)
            if plate:
                return plate
        return None

    def find2(self, img):
        lastp = None
        blobs = self.findBlobs(img)
        for b in blobs:
            bb=np.int0(cv2.boxPoints(b))
            lastp = cv2.boundingRect(bb)
            plate = self.checkBlob(b)
            if plate:
                return plate, lastp
        return None, lastp

    def findContours2(self, img):
        height = img.shape[0]
        width = img.shape[1]
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) # matrix of ones
        cnts = []
        for gray in cv2.split(img):# [cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)]:#
            dilated = cv2.dilate(src = gray, kernel = kernel, anchor = (-1,-1))
            blured = cv2.medianBlur(dilated, 7)
            small = cv2.pyrDown(blured, dstsize = (width / 2, height / 2))
            oversized = cv2.pyrUp(small, dstsize = (width, height)) 
            for thrs in xrange(0, 255, 26):
                if thrs == 0:
                    edges = cv2.Canny(oversized, threshold1 = 0, threshold2 = 50, apertureSize = 3)
                    next = cv2.dilate(src = edges, kernel = kernel, anchor = (-1,-1))
                else:
                    retval, next = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY)

                _, contours, hierarchy = cv2.findContours(next, mode = cv2.RETR_LIST, method = cv2.CHAIN_APPROX_SIMPLE)
                cnts.extend(contours)
            self.prepare(img)
            return cnts

    def findContours(self, img):
        i = self.prepare(img)
        _, cnts, hie = cv2.findContours(i, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
        return cnts

    def findBlobs(self, img):

        rects = []
        cnts = self.findContours(img)
        for c in cnts:
            c = c.reshape(-1, 2)
            if len(c) < 4:
                continue

            arcl = cv2.arcLength(c, True)
            approx = cv2.approxPolyDP(c, 0.02 * arcl, True)
            approx = approx.reshape(-1, 2)
            if len(approx) == 4 and cv2.contourArea(approx) > 3410:
                max_cos = np.max([self.angle_cos(approx[i], approx[(i+1) % 4], approx[(i+2) % 4]) for i in xrange(4)])
                if max_cos < 0.25:
                    rect = cv2.minAreaRect(approx)
                    w, h = rect[1]
                    ratio = float(w) / h if w>h else float(h) / w
                    if 2.4 < ratio < 4.2:
                        rects.append(rect)
        return rects

    def checkBlob(self, rect):
        ang = rect[2]
        w = rect[1][0]
        h = rect[1][1]
        if ang<-45:
            ang = ang + 90
            w = h
            h = rect[1][0]

        box = cv2.boxPoints(rect)
        box = np.int0(box)
        box = self.warp.order_points(box)
        roic = self.warp.transform(self.edged, box)
        roi =self.warp.transform(self.pre, box)
        
        (roich,roicw) = roic.shape[:2]
        nh = 143
        if roich>200:
            nw =  (roicw * nh)/roich
            roi =  cv2.resize(roi,(nw, nh), interpolation = cv2.INTER_LINEAR)
            roic =  cv2.resize(roic,(nw, nh), interpolation = cv2.INTER_LINEAR)


        letters = []
        i, cnts, _ = cv2.findContours(roic, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        h = roic.shape[0]
        if not cnts or len(cnts) < 5:
            return None

        for b in cnts:
            c = b.reshape(-1,2)
            if len(b)<3:
                continue
            r = cv2.boundingRect(c)
            ratio = float(r[3]) / r[2]
            if not 1.5 <= ratio <= 2.5 or r[3] < 0.5*h or r[0]==1:
                continue
            letters.append(r)
        return self.findChars(self.prepare2(roi), letters)


    def findChars(self, img, blobs):
        i = 0
        letters = [(img,p[1], p[0]) for p in enumerate(sorted(blobs, key=lambda b:b[0]))]
        plate = self.p.map(get_start, letters)
        return ''.join(filter(None,plate))

    def prepare(self, img, scale=True):
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        self.pre = cv2.GaussianBlur(gray, (5, 5), 0)
        self.edged = cv2.Canny(self.pre, 500, 1605,  apertureSize=5)

        if self.vlogger:
            self.vlogger.debug(VisualRecord("prepare", [self.pre, self.edged], fmt = "jpg"))
        return self.edged

    def prepare2(self, img, scale=True):
        kern = np.ones((3,5),np.uint8)
        th1 =  cv2.erode(img/2, kern, iterations = 1)
        ret,th = cv2.threshold(th1, 77, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

        if self.vlogger:
            self.vlogger.debug(VisualRecord("prepare2", [img,  th1, th], fmt = "jpg"))
        return th


    def angle_cos(self, p0, p1, p2):
        d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
        return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )
Ejemplo n.º 4
0
class PlateDetector(object):
    def __init__(self, vlogger = None):
        self.vlogger = vlogger
        self.pre= None
        self.edged= None
        self.warp= ImageBlobWarping()
        self.p= Pool(processes = 6)
        self.bnight= False

    def set_logger(self, logger):
        self.vlogger = logger

    def bestocr(self, ocrlst):
		ocr_overall_acc_lst= []
		imax= -1
		if len(ocrlst) == 0:
			return imax
		ocr_acc= 0
		#~ print ocrlst
		for ocritm in ocrlst:
			#~ print ocritm
			for det in ocritm:
				if det is not None and det[1] != None:
					try:
						ocr_acc = ocr_acc + det[1]**2
					except:
						pass
			if len(ocritm) > 0:
				ocr_acc /= len(ocritm)
				ocr_acc= ocr_acc**0.5
				print "ocr_acc: %.3f %%"%ocr_acc
				ocr_overall_acc_lst.append(round(ocr_acc,3))
		imax= max(ocr_overall_acc_lst)
		return ocr_overall_acc_lst.index(imax)

    """ Return best text recognized """
    def first(self, img):
        bbox= None
        code= None
        cnt= None
        blobs= self.findBlobs( img )
        ocrlst= []
        bboxlst= []
        cntslst= []
        print "original image shape:", img.shape
        for orig_rot_blob in blobs:
            bb= np.int0(cv2.boxPoints( orig_rot_blob ))
            bbox= cv2.boundingRect( bb )
            w= bbox[2]
            h= bbox[3]
            if (w > 2*h) and (w > 80) and (w < 200): # this should be relative to image dimensions
                code,cnts= self.ocr( orig_rot_blob )
                if code:
                    ocrlst.append( code )
                    bboxlst.append( bbox )
                    cntslst.append( cnts )
                    if len(code) == 6:
                        break
            # hardcoded -- width should not be higher than img.width / 8
            if (w > 2*h) and (w > 80) and (w < 400): # second stage without max size constraints
                code,cnts= self.ocr( orig_rot_blob )
                if code:
                    ocrlst.append( code )
                    bboxlst.append( bbox )
                    cntslst.append( cnts )
                    if len(code) == 6:
                        break

        if len( ocrlst ) > 0:
            ocr_best_index= self.bestocr( ocrlst )
            if ocr_best_index != -1:
                code= ocrlst[ ocr_best_index ]
                bbox= bboxlst[ ocr_best_index ]
                cnt= cntslst[ ocr_best_index ]
        else:
			print "none"

        return code, bbox

    def findBlobs(self, img):
        rects= []
        cnts= self.findContours(img)
        for c in cnts:
            c= c.reshape(-1, 2)
            if len(c) < 4:
                continue
            arcl= cv2.arcLength(c, True)
            approx= cv2.approxPolyDP(c, 0.02 * arcl, True)
            approx= approx.reshape(-1, 2)
            rect= cv2.minAreaRect(approx)
            w, h= rect[1]
            if len(approx) >= 4:
                if (h > 0) and (w > h):
                    ratio = float(w) / h
                    if 2.4 < ratio < 4.2:
                        rects.append(rect)
        return rects

    def ocr(self, rect):
        ang= rect[2]
        w,h= rect[1]
        if ang < -45:
            ang= ang + 90
            w= h
            h= rect[1][0]

        box= cv2.boxPoints(rect)
        box= np.int0(box)
        box= self.warp.order_points(box)
        letters= []
        code= []
        try:
            roic= self.warp.transform(self.edged, box)
            roi= self.warp.transform(self.pre, box)
            roi_orig= self.warp.transform(self.original_image, box)
        except:
            pass
            print "some error"
            return code
        
        (roich, roicw)= roic.shape[:2]
        nh= 143
        if roich > 200:
            nw= (roicw * nh)/roich
            roi= cv2.resize(roi,(nw, nh), interpolation= cv2.INTER_LINEAR)
            roic= cv2.resize(roic,(nw, nh), interpolation= cv2.INTER_LINEAR)

        #~ self.do_skeleton(roi)
        image_rect= self.prepare_for_ocr(roi)
        image_rect2= image_rect.copy()

        if self.vlogger:
            self.vlogger.debug(VisualRecord("candidate", [image_rect], fmt = "jpg"))

        i, cnts, hie_letters= cv2.findContours(image_rect, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        print "candidate shape", image_rect.shape
        if self.vlogger:
            self.vlogger.debug(VisualRecord("candidate after contours", [cv2.drawContours(roi_orig,cnts,-1,(0,255,0),1)], fmt = "jpg"))

        h= roic.shape[0]

        filtered_cnts= []
        
        for i,b in enumerate(cnts):

            hie_let= hie_letters[0][i]
            # [next, previous, first_child, parent]
            if hie_let[3] == -1: # if contour has no parent then continue with next
                continue

            c = b.reshape(-1,2)
            if len(b) < 3:  # ??
                continue

            r= cv2.boundingRect(c)
            
            # pantentes.txt - las letras miden 3.2cm y la patente completa 29.4cm
            if r[2] < (image_rect.shape[1] / 10):
                continue

            ratio= float(r[3]) / r[2]
            if not 1.5 <= ratio <= 2.5:
                continue
            
            letters.append(r)
            filtered_cnts.append(b)
        
        if len(letters) >= 4:
            for p in enumerate(sorted(letters, key= lambda b:b[0])):
                detected_letter= get_start((image_rect2, p[1], p[0]))
                code.append(detected_letter)
                print "letter detected: ",detected_letter
            
            if self.vlogger:
                self.vlogger.debug(VisualRecord("LETTER DETECTION", [cv2.drawContours(image_rect2,filtered_cnts,-1,(0,255,0),1)], fmt = "jpg"))
        return code, cnts

    def findContours(self, img):
        imgcopy= img.copy()
        if self.bnight:
            i= self.prepare_night(img)
        else:
            i= self.prepare_day(img)
        _,cnts, hie = cv2.findContours(i, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        if self.vlogger:
            if self.bnight:
                self.vlogger.debug(VisualRecord("contours", [cv2.drawContours(imgcopy,cnts,-1, (80,255,80),2),i], fmt = "jpg")) 
            else:
                self.vlogger.debug(VisualRecord("contours", [cv2.drawContours(imgcopy,cnts,-1, (255,120,120),2),i], fmt = "jpg")) 
        return cnts

####################################################################################################    

    def prepare_night(self, img):
        tinit= timer()
        self.original_image= img
        gray= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gauss_gray= cv2.GaussianBlur(gray, (5, 5), 0)
        max_gray= np.max(gray)
        std_gray= np.std(gray)
        saturated_night= np.uint8(( gray > ( max_gray - 2 * std_gray )) * 255) # argentina
        self.pre= gauss_gray
        self.edged= cv2.Canny(saturated_night, 10, 200,  apertureSize= 5)
        
        if self.vlogger:
            self.vlogger.debug(VisualRecord("thresholding > (max - 2 * std)", [saturated_night], fmt = "jpg"))
        print "e:%.3f"%(timer()-tinit)
        return self.edged

####################################################################################################
    def prepare_day(self, img):
        self.original_image= img
        gray= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gauss_gray= cv2.GaussianBlur(gray, (5, 5), 0)
        self.pre= gauss_gray
        self.edged= cv2.Canny(gauss_gray, 1000, 1700,  apertureSize= 5)
        if self.vlogger:
            self.vlogger.debug(VisualRecord("day prepare", [self.pre, self.edged], fmt = "jpg"))
        return self.edged

####################################################################################################
    def do_skeleton(self, img):
        size= np.size(img)
        skel= np.zeros(img.shape,np.uint8)
 
        ret,img = cv2.threshold(img,127,255,0)
        element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
        done = False
 
        while( not done):
            eroded= cv2.erode(img,element)
            temp= cv2.dilate(eroded,element)
            temp= cv2.subtract(img,temp)
            skel= cv2.bitwise_or(skel,temp)
            img= eroded.copy()
            zeros= size- cv2.countNonZero(img)
            if zeros == size:
                done= True
        if self.vlogger:
            self.vlogger.debug(VisualRecord("pancro", [img, skel], fmt = "jpg"))
                
####################################################################################################
    def angle_cos(self, p0, p1, p2):
        d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
        return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )

    def prepare_for_ocr(self, img, scale=True):
        #~ print "shape", img.shape
        kern= cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
		# http://docs.opencv.org/master/d5/daf/tutorial_py_histogram_equalization.html#gsc.tab=0

        clahe= cv2.createCLAHE(clipLimit=2.0, tileGridSize=(5,5))
        ims= clahe.apply(img)

        ret,th= cv2.threshold(ims, 150, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

        th1= cv2.morphologyEx(th, cv2.MORPH_CLOSE, kern)
        
        th2= self.create_rect(th1)
        if self.vlogger:
            self.vlogger.debug(VisualRecord("prepare_for_ocr", [img,  ims, th], fmt = "jpg"))
        self.calc_stats(img)
        return th2

    def calc_stats(self, img):
        uniques= np.unique(np.ravel(img))
        hist, bins= np.histogram(img, bins= uniques)
        mxcount= np.max(hist)
        #~ print hist
        #~ print bins
        print "min-",np.min(uniques),"max-",np.max(uniques)
        print "unique values-", len(uniques)
        print "mxcount-", mxcount, "index-", np.where(hist == mxcount)[0][0], "DN-", bins[np.where(hist == mxcount)][0]

    def create_rect(self, img):
        dims= img.shape
        imgcop= img.copy()
        imgcop[0:4,0:dims[1]]= 255
        imgcop[dims[0]-2:dims[0],0:dims[1]]= 255

        if self.vlogger:
            self.vlogger.debug(VisualRecord("CREATE RECT", [imgcop], fmt = "jpg"))
        return imgcop