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
 
import scipy.cluster
 
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):
 
	arr=np.reshape(img,(-1,3)).astype(np.float)
 
	colors=np.array([[0,0,0],[255,255,255],[193,165,116]],np.float)
 
	print(colors)
 
@@ -24,44 +35,85 @@ def quantize(img,centers):
 
	data=np.reshape(img,(-1,3))
 
	(keys,dists)=scipy.cluster.vq.vq(data,centers)
 
	pixels=np.array([centers[k] for k in keys],dtype=np.uint8).reshape(origShape)
 
	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])
 
	filename=os.path.basename(filepath)
 
	(x1,y1,x2,y2)=computeBoundingBox(annotations[filename][0])
 
	(w,h)=(x2-x1,y2-y1)
 
@@ -89,7 +141,28 @@ if __name__=="__main__":
 
	show(stones)
 

	
 
	stoneDims=(w/19,h/19)
 
	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)