Changeset - 8be76da66456
[Not reviewed]
default
0 1 0
Laman - 6 years ago 2019-01-10 16:39:41

exp: connecting segmented stones into lines
1 file changed with 84 insertions and 11 deletions:
0 comments (0 inline, 0 general)
exp/stone_detect.py
Show inline comments
 
import sys
 
sys.path.append("../src")
 

	
 
import os
 
import sys
 
import math
 
import heapq
 

	
 
import cv2 as cv
 
import numpy as np
 
@@ -8,6 +12,13 @@ import scipy.ndimage
 

	
 
from annotations import DataFile,computeBoundingBox
 
from hough import show
 
from analyzer.epoint import EPoint
 

	
 

	
 
class NeighboringPoint(EPoint):
 
	def __init__(self,x,y):
 
		super().__init__(x,y)
 
		self.neighbours=[]
 

	
 

	
 
def kmeans(img):
 
@@ -27,38 +38,79 @@ def quantize(img,centers):
 
	return pixels
 

	
 

	
 
def filterContours(contours,bwImg,stoneDims):
 
def filterStones(contours,bwImg,stoneDims):
 
	contourImg=cv.cvtColor(bwImg,cv.COLOR_GRAY2BGR)
 
	res=[]
 
	for (i,c) in enumerate(contours):
 
		keep=True
 
		print(i)
 
		moments=cv.moments(c)
 
		center=(moments["m10"]/(moments["m00"] or 1), moments["m01"]/(moments["m00"] or 1))
 
		print("center:", center)
 
		area=cv.contourArea(c)
 
		print("area:",area)
 
		(x,y,w,h)=cv.boundingRect(c)
 
		print("bounding box:",(x,y,w,h))
 
		if w>stoneDims[0] or h>stoneDims[1]*1.3 or w<2 or h<2:
 
			cv.drawMarker(contourImg,tuple(map(int,center)),(0,0,255),cv.MARKER_TILTED_CROSS,12)
 
			keep=False
 
		coverage1=area/(w*h or 1)
 
		print("coverage1:",coverage1)
 
		hull=cv.convexHull(c)
 
		coverage2=area/(cv.contourArea(hull) or 1)
 
		print("coverage2:",coverage2)
 
		if coverage2<0.8:
 
			cv.drawMarker(contourImg,tuple(map(int,center)),(0,127,255),cv.MARKER_DIAMOND,12)
 
			keep=False
 
		print()
 
		if keep:
 
			res.append(c)
 
			res.append((EPoint(*center),c))
 
			cv.drawMarker(contourImg,tuple(map(int,center)),(255,0,0),cv.MARKER_CROSS)
 
	print("accepted:",len(res))
 
	print("rejected:",len(contours)-len(res))
 
	show(contourImg)
 
	return res
 

	
 

	
 
def computeDistances(points):
 
	n=len(points)
 
	res=np.zeros((n,n),dtype=np.float32)
 

	
 
	for (i,a) in enumerate(points):
 
		for (j,b) in enumerate(points):
 
			if j<i: continue
 
			elif j==i: res[i,j]=0
 
			else:
 
				res[i,j]=res[j,i]=a.dist(b)
 

	
 
	return res
 

	
 

	
 
def collectNeighbours(points):
 
	# we could do this in O(n log n)
 
	# doi:10.1007/BF02187718
 
	# https://link.springer.com/content/pdf/10.1007/BF02187718.pdf
 
	""":param points: [EPoint, ...]
 
	:return: [(k_i,dist_i) for i in range(4)]"""
 
	neighborhood=[NeighboringPoint(p.x,p.y) for p in points]
 
	dists=computeDistances(points)
 
	for (i,a) in enumerate(points):
 
		neighbours=heapq.nsmallest(4,enumerate(dists[i]),key=lambda x: x[1] if x[1]>0 else 1000)
 
		neighborhood[i].neighbours=[neighborhood[j] for (j,d) in neighbours]
 
	return neighborhood
 

	
 

	
 
def growLine(r,s):
 
	""":param r: NeighboringPoint
 
	:param s: NeighboringPoint
 
	:return: NeighboringPoint or None"""
 
	u=s-r
 
	alpha=math.atan2(u.y,u.x)
 
	t=None
 
	beta=alpha+math.pi # -alpha
 
	for t_ in s.neighbours:
 
		v=t_-s
 
		beta_=math.atan2(v.y,v.x) # beta_ in (-pi, pi]
 
		if abs(abs(alpha-beta_)-math.pi)>abs(abs(alpha-beta)-math.pi):
 
			beta=beta_
 
			t=t_
 
	if abs(alpha-beta)<math.pi/12: return t
 
	else: return None
 

	
 

	
 
if __name__=="__main__":
 
	filepath=sys.argv[1]
 
	annotations=DataFile(sys.argv[2])
 
@@ -92,4 +144,25 @@ if __name__=="__main__":
 
	print("stone dims:",tuple(x/2 for x in stoneDims),"-",stoneDims)
 

	
 
	(contours,hierarchy)=cv.findContours(stones,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
 
	filterContours(contours,stones,stoneDims)
 
	stoneLocs=filterStones(contours,stones,stoneDims)
 
	neighborhood=collectNeighbours([point for (point,contour) in stoneLocs])
 

	
 
	linesImg=cv.cvtColor(np.zeros((h,w),np.uint8),cv.COLOR_GRAY2BGR)
 
	cv.drawContours(linesImg,[c for (point,c) in stoneLocs],-1,(255,255,255),-1)
 
	for p in neighborhood:
 
		cv.drawMarker(linesImg,(int(p.x),int(p.y)),(255,0,0),cv.MARKER_CROSS)
 

	
 
	for p in neighborhood:
 
		for q in p.neighbours:
 
			length=1
 
			while True:
 
				q_=growLine(p,q)
 
				if q_:
 
					q=q_
 
					length+=1
 
				else: break
 
			if length>1 or True:
 
				print(length,p,q)
 
			cv.line(linesImg,(int(p.x),int(p.y)),(int(q.x),int(q.y)),(255,255,0),min((length+1)//2,3))
 
	show(linesImg)
 
	cv.imwrite("/tmp/img.png",linesImg)
0 comments (0 inline, 0 general)