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_)=2*h: continue if y=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()