Changeset - 90090fca08f9
[Not reviewed]
default
0 1 0
Laman - 6 years ago 2019-02-17 10:44:37

experiment with double Hough transform
1 file changed with 114 insertions and 41 deletions:
exp/hough.py
114
41
0 comments (0 inline, 0 general)
exp/hough.py
Show inline comments
 
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()
0 comments (0 inline, 0 general)