# HG changeset patch # User Laman # Date 2019-02-17 10:44:37 # Node ID 90090fca08f902ba4d88f29469c583f28ef82cfe # Parent 7c268e382b96e468bfbf9c390a2e7e92975c4187 experiment with double Hough transform diff --git a/exp/hough.py b/exp/hough.py --- a/exp/hough.py +++ b/exp/hough.py @@ -1,7 +1,6 @@ import sys sys.path.append("../src") -import os import math from datetime import datetime import logging as log @@ -10,9 +9,98 @@ import numpy as np import scipy.optimize import cv2 as cv -from annotations import DataFile,computeBoundingBox +from geometry import Line from analyzer.epoint import EPoint +DEBUG=True + + +class BaseHough: + def __init__(self,width,height): + self._diagLen=int(np.sqrt(height**2+width**2))+1 + self._center=(width//2,height//2) + self._acc=np.zeros((180,self._diagLen),dtype=np.int32) + + def update(self,x,y,weight=1): + """:param x: number, 0 <= x < width + :param y: number, 0 <= y < height""" + for alphaDeg in range(0,180): + d=self._computeDist(x,y,alphaDeg)+self._diagLen//2 + self._acc[(alphaDeg,d)]+=weight + + def extract(self,n): + shift=self._diagLen//2 + peaks=sorted(list(findPeaks(self._acc)),key=lambda rc: self._acc[rc],reverse=True) + peaks=self._filterClose(peaks)[:n] + log.debug("detected peaks: %s",[(alpha,d-shift) for (alpha,d) in peaks]) + + img=self._createImg() + img=self._markPeaks(img,self._filterClose(peaks)) + self.show(img) + + res=[] + for (alphaDeg,d) in peaks: + alphaRad=alphaDeg*math.pi/180 + baseLine=Line(alphaRad,0) + dd=baseLine.distanceTo(EPoint(*self._center)) # to shift d from the center to 0,0 + res.append(Line(alphaRad, dd+d-shift)) + log.debug("detected lines: %s",res) + return res + + def _computeDist(self,x,y,alphaDeg): + """Compute the distance of a line with the provided alphaDeg declination and passing the (x,y) point to the image center. + The returned distance might be negative (meaning the angle is in fact alpha+180).""" + alphaRad=alphaDeg*math.pi/180 + (x0,y0)=self._center + (dx,dy)=(x-x0,y-y0) + d=dx*math.cos(alphaRad)+dy*math.sin(alphaRad) + return round(d) + + def _filterClose(self,peaks): # a naive implementation + """Discard points with Euclidean distance on the original image lower than 10. + From such pairs keep only the one with a higher value in the accumulator. + This can delete a series of points. If a-b and b-c are close and a>b>c, only a is kept.""" + minDist=13 + center=EPoint(*self._center) + res=[] + for (alphaDeg,d) in peaks: + alphaRad=alphaDeg*math.pi/180 + point=EPoint.fromPolar((alphaRad,d),center) + ctrl=True + for (betaDeg,e) in peaks: + betaRad=betaDeg*math.pi/180 + point_=EPoint.fromPolar((betaRad,e),center) + if point.dist(point_)<minDist and self._acc[(alphaDeg,d)]<self._acc[(betaDeg,e)]: + ctrl=False + if ctrl: res.append((alphaDeg,d)) + return res + + def show(self,img=None): + if not DEBUG: return + if img is None: img=self._createImg() + + show(img,"Hough transform accumulator") + + def _createImg(self): + maxVal=self._acc.max() + arr=np.expand_dims(np.uint8(255*self._acc//maxVal),axis=2) + img=np.concatenate((arr,arr,arr),axis=2) + + (h,w)=img.shape[:2] + + for x in range(0,w,4): # y axis + img[h//2,x]=[255,255,255] + for y in range(0,h,4): + img[y,w//2]=[255,255,255] + + return img + + def _markPeaks(self,img,peaks): + colors=[[255,0,0],[255,255,0],[0,255,0],[0,255,255],[0,0,255]] + for (i,(alpha,d)) in enumerate(peaks[:38]): + cv.drawMarker(img,(d,alpha),colors[i//9],cv.MARKER_TILTED_CROSS) + return img + class HoughTransform: def __init__(self,img): @@ -33,15 +121,19 @@ class HoughTransform: peaks=self._filterClose(peaks) peaks.sort(key=lambda rc: rc[0]) log.debug("detected peaks: %s",peaks) - (alpha,beta)=self._detectDominantAngles(peaks) + + h2=BaseHough(self._diagLen,180+90) + for (alpha,d) in peaks: + h2.update(d+shift,alpha) + if alpha<90: + h2.update(shift-d,alpha+180) + lines=h2.extract(3) img=self._createImg() img=self._markPeaks(img,self._filterClose(allPeaks[:38])) - doublePeaks=peaks+[(alpha+180,-d) for (alpha,d) in peaks] - params=self._computeGridParams([(gamma,d+shift) for (gamma,d) in doublePeaks if alpha<=gamma<=alpha+self._angleBandwidth]) - self._drawGridCurve(img,params,0) - params=self._computeGridParams([(gamma,d+shift) for (gamma,d) in doublePeaks if beta<=gamma<=beta+self._angleBandwidth]) - self._drawGridCurve(img,params,1) + + for (i,line) in enumerate(lines): + self.drawLine(img,line,i) self.show(img) def update(self,img,weight=1): @@ -141,13 +233,26 @@ class HoughTransform: (h,w)=img.shape[:2] curve=lambda x: a*x**3+b*x**2+c*x+d for x in range(0,w,3): - y=int(curve(x)) + y=round(curve(x)) if y<0 or y>=2*h: continue if y<h: img[y,x]=color else: img[y%h,-x]=color + def drawLine(self,img,line,colorKey=0): + colors=[[0,255,255],[255,0,255],[255,255,0]] + color=colors[colorKey] + (h,w)=img.shape[:2] + (a,b,c)=line.toNormal() + print("%",a,b,c) + if b==0: return + for x in range(1,w,3): + y=round((-c-a*x)/b) + (0 if b>=0 else 180) + if y<0 or y>=h: continue + img[y,x]=color + def findPeaks(arr2d): # a naive implementation + """Scan 8-neighbourhood and for each peak or top plateau yield one point. For plateaus yield the """ (h,w)=arr2d.shape neighbours=[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] for r in range(h): @@ -207,35 +312,3 @@ def houghLines(bwImg): cv.line(colorImg,(x1,y1),(x2,y2),(0,255,0),1) show(colorImg) - - -if __name__=="__main__": - i=sys.argv[1] - annotations=DataFile("/home/laman/Projekty/python/oneEye/images/annotations.json.gz") - filename="{0}.jpg".format(i) - img=cv.imread(os.path.join("/home/laman/Projekty/python/oneEye/images/",filename)) - (x1,y1,x2,y2)=computeBoundingBox(annotations[filename][0]) - img=img[y1:y2, x1:x2, :] - # blurred=cv.GaussianBlur(img,(5,5),0) - # small=cv.resize(img,None,fx=0.5,fy=0.5,interpolation=cv.INTER_AREA) - small=img - clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) - gray=cv.cvtColor(small,cv.COLOR_BGR2GRAY) - # gray=clahe.apply(gray) - show(gray) - edges=cv.Canny(gray,70,130) - show(edges) - edges=filterHor(edges)+filterVert(edges)+filterDiag(edges) - show(edges) - - - # kernel = np.ones((2,2),np.uint8) - # edges = cv.morphologyEx(edges, cv.MORPH_DILATE, kernel) - # show(edges) - # edges=cv.morphologyEx(edges,cv.MORPH_ERODE,kernel) - # show(edges) - colorEdges=cv.cvtColor(edges,cv.COLOR_GRAY2BGR) - - # houghLines(edges) - h=HoughTransform(edges) - h.extract()