Files @ a00c974af8ae
Branch filter:

Location: OneEye/exp/kerokero/prepare_data.py - annotation

Laman
experimental single corner Hakugen
655956f6ba89
655956f6ba89
655956f6ba89
db53fefbf557
655956f6ba89
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
a9c02a5b2bfc
655956f6ba89
655956f6ba89
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
a9c02a5b2bfc
a9c02a5b2bfc
a9c02a5b2bfc
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
ecf98a415d97
fad34516870e
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
fad34516870e
fad34516870e
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
5f42b982809c
655956f6ba89
9c78e6f2e2ea
006c6f1aab13
655956f6ba89
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
db53fefbf557
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
a00c974af8ae
db53fefbf557
a00c974af8ae
db53fefbf557
db53fefbf557
655956f6ba89
ecf98a415d97
655956f6ba89
655956f6ba89
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
ecf98a415d97
655956f6ba89
655956f6ba89
a9c02a5b2bfc
a9c02a5b2bfc
db53fefbf557
655956f6ba89
ecf98a415d97
655956f6ba89
655956f6ba89
d9cf0ed8e7fd
db53fefbf557
a00c974af8ae
a00c974af8ae
a00c974af8ae
a00c974af8ae
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
a9c02a5b2bfc
a9c02a5b2bfc
a9c02a5b2bfc
a9c02a5b2bfc
a9c02a5b2bfc
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
5f42b982809c
5f42b982809c
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
655956f6ba89
9483b964f560
9483b964f560
9483b964f560
9483b964f560
9483b964f560
9483b964f560
9483b964f560
9483b964f560
import os
import sys
import re
import math
import random
import logging as log

import numpy as np
import cv2 as cv

import config as cfg
sys.path.append("..")
sys.path.append("../../src")
from annotations import DataFile,computeBoundingBox,Corners,EPoint,Board
from geometry import Line
from kerokero.transformation_matrices import getIdentity,getRotation,getTranslation,getScale,getMirroring,getProjection

random.seed(361)


class Stats:
	counts=[0,0,0,0]


class Sample:
	SIDE=224

	def __init__(self,img,grid):
		""":param img: a greyscale image as a 2D np.uint8
		:param grid: iterable of 4 EPoints, ie. Corners"""
		self.img=img
		self.grid=grid

	def transform(self):
		""":return: (img, grid), where img is a 2D np.float32 with values in (0,1),
		grid [(float) x, (float) y, ...], with x, y in (-1,1)"""
		center=self._getCenter()
		m=getIdentity()
		t1=getTranslation(-center.x,-center.y)
		proj=getProjection()
		rot=getRotation()
		mir=getMirroring()
		for mi in [t1,mir,proj,rot]:
			m=np.matmul(mi,m)
		m=np.matmul(self._computeCrop(m),m)
		img=cv.warpPerspective(self.img,m,(self.SIDE,self.SIDE))
		img=np.uint8(img)
		grid=Corners(c.transform(m) for c in self.grid)
		grid=list(map(lambda p: list(2*p/self.SIDE-EPoint(1,1)), grid))
		return (img,grid)

	def rectify(self):
		x1=self.SIDE*0.1
		x2=self.SIDE*0.9
		abcd=list(map(list,self.grid))
		destPoints=[(x1,x1),(x1,x2),(x2,x2),(x2,x1)]
		abcd_=list(map(list, (EPoint(x,y)+self._createNoise() for (x,y) in destPoints)))
		m=cv.getPerspectiveTransform(np.float32(abcd),np.float32(abcd_))
		img=cv.warpPerspective(self.img,m,(self.SIDE,self.SIDE))
		img=np.uint8(img)
		grid=Corners(c.transform(m) for c in self.grid)
		grid=list(map(lambda p: list(2*p/self.SIDE-EPoint(1,1)), grid))
		return (img,grid)

	def cut(self):
		width=max(p.x for p in self.grid)-min(p.x for p in self.grid)
		height=max(p.y for p in self.grid)-min(p.y for p in self.grid)
		kx=width/4
		ky=height/4
		n=self.SIDE
		for p in self.grid:
			shift=self._createNoise(0.2)
			abcd=[[p.x-kx,p.y-ky],[p.x-kx,p.y+ky],[p.x+kx,p.y+ky],[p.x+kx,p.y-ky]]
			abcd_=[[shift.x,shift.y],[shift.x,n+shift.y],[n+shift.x,n+shift.y],[n+shift.x,shift.y]]
			m=cv.getPerspectiveTransform(np.float32(abcd),np.float32(abcd_))
			t1=getTranslation(-n/2,-n/2)
			mir=getMirroring()
			proj=getProjection()
			rot=getRotation()
			t2=getTranslation(n/2,n/2)
			for mi in [t1,mir,proj,rot,t2]:
				m=np.matmul(mi,m)
			img=cv.warpPerspective(self.img,m,(self.SIDE,self.SIDE))
			img=np.uint8(img)
			point=p.transform(m)*2/self.SIDE-EPoint(1,1)
			yield (img,[point.x,point.y])

	def _getCenter(self):
		(a,b,c,d)=self.grid
		p=Line.fromPoints(a,c)
		q=Line.fromPoints(b,d)
		return p.intersect(q)

	def _computeCrop(self,m):
		grid=Corners(c.transform(m) for c in self.grid)
		(x1,y1,x2,y2)=computeBoundingBox(grid)
		(wg,hg)=(x2-x1,y2-y1)
		(left,top,right,bottom)=[random.uniform(0.05,0.2) for i in range(4)]
		t2=getTranslation(left*wg-x1, top*hg-y1)
		scale=getScale(self.SIDE/(wg*(1+left+right)), self.SIDE/(hg*(1+top+bottom)))
		return np.matmul(scale,t2)

	def _createNoise(self,mag=0.05):
		alpha=random.uniform(0,math.pi*2)
		d=random.uniform(0,self.SIDE*mag)
		return EPoint(math.cos(alpha)*d, math.sin(alpha)*d)

	def show(self):
		img=cv.cvtColor(self.img,cv.COLOR_GRAY2BGR)
		for c in self.grid:
			cv.circle(img,(int(c.x),int(c.y)),3,[0,255,0],-1)
		img=cv.resize(img,(self.SIDE*2,self.SIDE*2))
		show(img)


def traverseDirs(root):
	stack=[root]
	while len(stack)>0:
		d=stack.pop()
		contents=sorted(os.scandir(d),key=lambda f: f.name,reverse=True)
		if any(f.name=="annotations.json.gz" for f in contents):
			log.info(d)
			yield d
		for f in contents:
			if f.is_dir(): stack.append(f.path)


def harvestDir(path):
	annotations=DataFile(os.path.join(path,"annotations.json.gz"))
	imgFilter=lambda f: f.is_file() and re.match(r".*\.(jpg|jpeg|png|gif)$", f.name.lower())
	files=sorted(filter(imgFilter,os.scandir(path)),key=lambda f: f.name)
	boards=annotations["."]
	for f in files:
		grade=annotations.get(f.name,[Board()])[0].grade
		Stats.counts[grade]+=1
		if not Board.UNSET<grade<=Board.GOOD: continue
		img=cv.imread(f.path)
		img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
		for b in boards:
			sample=Sample(img,b.grid)
			# sample.show()
			# (transformedImg,label)=sample.transform()
			# (transformedImg,label)=sample.rectify()
			for (transformedImg,label) in sample.cut():
				Sample(np.uint8(transformedImg),[(EPoint(*label)+EPoint(1,1))*Sample.SIDE/2]).show()
				yield (transformedImg,label)


def loadDataset(root):
	testRatio=0.1
	trainRatio=1-testRatio
	images=[]
	labels=[]
	for d in traverseDirs(root):
		for (img,label) in harvestDir(d):
			images.append(img)
			labels.append(label)
	log.info("clear images: %s",Stats.counts[1])
	log.info("good images: %s",Stats.counts[2])
	log.info("poor images: %s",Stats.counts[3])
	log.info("unset images: %s",Stats.counts[0])
	log.info("total: %s",sum(Stats.counts))
	n=len(images)
	keys=list(range(n))
	random.shuffle(keys)
	images=[images[k] for k in keys]
	labels=[labels[k] for k in keys]
	m=int(n*trainRatio)
	return (
		(np.uint8(images[:m]),np.float32(labels[:m])),
		(np.uint8(images[m:]),np.float32(labels[m:]))
	)


def show(img,filename="x"):
	cv.imshow(filename,img)
	cv.waitKey(0)
	cv.destroyAllWindows()


if __name__=="__main__":
	((trainImages,trainLabels),(testImages,testLabels))=loadDataset(sys.argv[1])
	np.savez_compressed(
		sys.argv[2],
		trainImages=trainImages,
		trainLabels=trainLabels,
		testImages=testImages,
		testLabels=testLabels
	)