Changeset - a00c974af8ae
[Not reviewed]
default
0 3 0
Laman - 6 years ago 2019-06-11 17:27:57

experimental single corner Hakugen
3 files changed with 36 insertions and 13 deletions:
0 comments (0 inline, 0 general)
exp/kerokero/prepare_data.py
Show inline comments
 
@@ -41,105 +41,129 @@ class Sample:
 
		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):
 
	def _createNoise(self,mag=0.05):
 
		alpha=random.uniform(0,math.pi*2)
 
		d=random.uniform(0,self.SIDE*0.05)
 
		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()
 
			# Sample(np.uint8(transformedImg),map(lambda c: (EPoint(*c)+EPoint(1,1))*Sample.SIDE/2,label)).show()
 
			# (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 (
exp/kerokero/test.py
Show inline comments
 
@@ -4,38 +4,38 @@ import logging as log
 
import numpy as np
 
from keras.models import load_model
 
import keras.metrics
 

	
 
from prepare_data import loadDataset,Sample
 
from analyzer.epoint import EPoint
 
from analyzer.corners import Corners
 
from k_util import averageDistance,generateData
 
import config as cfg
 

	
 
keras.losses.averageDistance=averageDistance
 
keras.metrics.averageDistance=averageDistance
 

	
 
parser=argparse.ArgumentParser()
 
parser.add_argument("model")
 
parser.add_argument("data")
 
args=parser.parse_args()
 

	
 
model=load_model(args.model)
 
model.summary()
 

	
 
log.info("loading data...")
 
with np.load(args.data) as data:
 
	testImages=(np.float32(data["testImages"])/128-1).reshape((-1,224,224,1))
 
	testLabels=data["testLabels"].reshape((-1,4,2))
 
	testLabels=data["testLabels"].reshape((-1,1,2))
 
log.info("done")
 

	
 
log.info(model.evaluate(testImages,testLabels))
 

	
 
for img in testImages:
 
	label=model.predict(np.reshape(img,(1,224,224,1)))
 
	print(label)
 
	points=[]
 
	for i in range(4):
 
	for i in range(1):
 
		points.append(EPoint((label[0][i][0]+1)*112,(label[0][i][1]+1)*112))
 
	corners=Corners(points)
 
	corners=points
 
	sample=Sample(np.uint8((img+1)*128),corners)
 
	sample.show()
exp/kerokero/train.py
Show inline comments
 
import os
 
import math
 
from time import time
 
import argparse
 
import logging as log
 

	
 
import numpy as np
 
from keras.layers import Conv2D,Dropout,Dense,Flatten,MaxPooling2D,BatchNormalization,GlobalAveragePooling2D,Reshape
 
from keras.models import Sequential,load_model
 
from keras.callbacks import TensorBoard,ModelCheckpoint
 
import keras.metrics
 

	
 
import config as cfg
 
from k_util import averageDistance,generateData
 

	
 
keras.losses.averageDistance=averageDistance
 
keras.metrics.averageDistance=averageDistance
 

	
 
parser=argparse.ArgumentParser()
 
parser.add_argument("data")
 
parser.add_argument("--load_model")
 
parser.add_argument("--save_model",default="/tmp/gogo-{0:03}.h5")
 
parser.add_argument("--load_hints")
 
parser.add_argument("--log_dir",default="/tmp/tflogs")
 
parser.add_argument("--epochs",type=int,default=100)
 
parser.add_argument("--initial_epoch",type=int,default=0)
 
args=parser.parse_args()
 

	
 

	
 
def createFullyConnected():
 
	model=Sequential([
 
		Flatten(input_shape=(224,224)),
 
		Dense(128, activation="relu"),
 
		Dropout(0.1),
 
		Dense(64, activation="relu"),
 
		Dense(8)
 
	])
 

	
 
	model.compile(
 
		optimizer='adam',
 
		loss='mse',
 
		metrics=['mae','accuracy']
 
	)
 
	return model
 

	
 
def createCNN():
 
	model=Sequential()
 

	
 
	model.add(BatchNormalization(input_shape=(224,224,1)))
 

	
 
	model.add(Conv2D(24,(5,5),padding="same",kernel_initializer="he_normal",activation="relu",input_shape=(224,224,1),data_format="channels_last"))
 
	model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid"))
 

	
 
	model.add(Conv2D(36,(5,5),activation="relu"))
 
	model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid"))
 

	
 
	model.add(Conv2D(48,(5,5),activation="relu"))
 
	model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid"))
 

	
 
	model.add(Conv2D(64,(3,3),activation="relu"))
 
	model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid"))
 

	
 
	model.add(Conv2D(64,(3,3),activation="relu"))
 

	
 
	model.add(GlobalAveragePooling2D())
 

	
 
	model.add(Dense(500,activation="relu"))
 
	model.add(Dense(90,activation="relu"))
 
	model.add(Dense(8))
 
	model.add(Reshape((4,2)))
 
	model.add(Dense(2))
 
	model.add(Reshape((1,2)))
 

	
 
	model.compile(optimizer="rmsprop",loss=averageDistance,metrics=["mae","accuracy"])
 
	model.compile(optimizer="rmsprop",loss="mae",metrics=["mae","accuracy"])
 
	return model
 

	
 

	
 
if args.load_model:
 
	model=load_model(args.load_model)
 
else:
 
	model=createCNN()
 
	model.summary()
 

	
 
log.info("loading data...")
 
with np.load(args.data) as data:
 
	trainImages=(np.float32(data["trainImages"])/128-1).reshape((-1,224,224,1))
 
	trainLabels=data["trainLabels"].reshape((-1,4,2))
 
	trainLabels=data["trainLabels"].reshape((-1,1,2))
 
	testImages=(np.float32(data["testImages"])/128-1).reshape((-1,224,224,1))
 
	testLabels=data["testLabels"].reshape((-1,4,2))
 
	testLabels=data["testLabels"].reshape((-1,1,2))
 
log.info("done")
 

	
 
n=len(trainImages)
 
k=round(n*0.9)
 
n_=n-k
 
(trainImages,valImages)=(np.float32(trainImages[:k]),np.float32(trainImages[k:]))
 
(trainLabels,valLabels)=(np.float32(trainLabels[:k]),np.float32(trainLabels[k:]))
 

	
 
tensorboard=TensorBoard(log_dir=os.path.join(args.log_dir,"{}".format(time())))
 
checkpoint=ModelCheckpoint(args.save_model,monitor="val_loss",period=10)
 

	
 
model.fit_generator(
 
	generateData(trainImages,trainLabels,batch_size=20),
 
	epochs=args.epochs,
 
	initial_epoch=args.initial_epoch,
 
	steps_per_epoch=math.ceil(n_/20),
 
	validation_data=generateData(valImages,valLabels,batch_size=20),
 
	validation_steps=math.ceil(k/20),
 
	callbacks=[tensorboard,checkpoint]
 
)
 

	
 
print(model.evaluate(testImages,testLabels))
0 comments (0 inline, 0 general)