Changeset - db53fefbf557
[Not reviewed]
default
0 4 1
Laman - 6 years ago 2019-06-09 21:10:09

Hakugen detection module
5 files changed with 87 insertions and 44 deletions:
0 comments (0 inline, 0 general)
exp/dochi.py
Show inline comments
 
import os
 
import time
 
import argparse
 
import logging as log
 

	
 
import cv2 as cv
 
import numpy as np
 
import keras
 
from keras.models import load_model
 
from PIL import Image,ImageDraw
 
from PIL import Image
 

	
 
from epoint import EPoint
 
import exp_config as cfg
 
from kerokero.k_util import averageDistance
 

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

	
 
model=load_model(cfg.dochiModel)
 
SIDE=224
 

	
 

	
 
def locateGrid(img):
 
	t1=time.time()
 
	(width,height)=img.size
 
	normedImg=img.convert("L").resize((224,224),resample=Image.BILINEAR)
 
	npImg=np.array(normedImg.getdata()).reshape((224,224,1)).astype(np.float32)
 
	npImg=npImg/128-1
 

	
 
	label=model.predict(np.reshape(npImg,(1,224,224,1)))
 
	points=[]
 
	for i in range(4):
 
		points.append(EPoint((label[0][i][0]+1)*(width/2),(label[0][i][1]+1)*(height/2)))
 
		points.append([(label[0][i][0]+1)*(width/2),(label[0][i][1]+1)*(height/2)])
 
	t=time.time()-t1
 
	log.info("grid located in {0:.3}s".format(t))
 
	return points
 

	
 

	
 
if __name__=="__main__":
 
	parser=argparse.ArgumentParser()
 
	parser.add_argument("-i","--input",nargs="+")
 
	parser.add_argument("-o","--output_dir",required=True)
 
	args=parser.parse_args()
 

	
 
	for image_path in args.input:
 
		image=Image.open(image_path)
 
		points=locateGrid(image)
 
		drawer=ImageDraw.Draw(image)
 
		for p in points:
 
			drawer.ellipse((p.x-2,p.y-2,p.x+2,p.y+2),fill="#00ff00")
 
		image.save(os.path.join(args.output_dir,os.path.basename(image_path)))
 
		x1=SIDE*0.1
 
		x2=SIDE*0.9
 
		destPoints=[(x1,x1),(x1,x2),(x2,x2),(x2,x1)]
 
		m=cv.getPerspectiveTransform(np.float32(points),np.float32(destPoints))
 
		img=cv.warpPerspective(np.uint8(image),m,(SIDE,SIDE))
 
		img=cv.cvtColor(img,cv.COLOR_BGR2RGB)
 
		cv.imwrite(os.path.join(args.output_dir,os.path.basename(image_path)),img)
exp/exp_config.py
Show inline comments
 
@@ -4,16 +4,17 @@ import logging as log
 

	
 

	
 
log.basicConfig(level=log.INFO,format="%(asctime)s %(levelname)s: %(message)s")
 
thisDir=os.path.dirname(__file__)
 

	
 
with open(os.path.join(thisDir,"config.json")) as f:
 
	cfg=json.load(f)
 

	
 
INTERACTIVE=False
 
imgDir="/tmp/oneEye"
 
sansaModel=cfg.get("sansaModel")
 
dochiModel=cfg.get("dochiModel")
 
hakugenModel=cfg.get("hakugenModel")
 
i=1
 

	
 
if not os.path.exists(imgDir):
 
	os.mkdir(imgDir)
exp/hakugen.py
Show inline comments
 
new file 100644
 
import os
 
import time
 
import argparse
 
import logging as log
 

	
 
import numpy as np
 
import keras
 
from keras.models import load_model
 
from PIL import Image,ImageDraw
 

	
 
from epoint import EPoint
 
import exp_config as cfg
 
from kerokero.k_util import averageDistance
 

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

	
 
model=load_model(cfg.hakugenModel)
 

	
 

	
 
def locateGrid(img):
 
	t1=time.time()
 
	(width,height)=img.size
 
	normedImg=img.convert("L")
 
	npImg=np.array(normedImg.getdata()).reshape((224,224,1)).astype(np.float32)
 
	npImg=npImg/128-1
 

	
 
	label=model.predict(np.reshape(npImg,(1,224,224,1)))
 
	points=[]
 
	for i in range(4):
 
		points.append(EPoint((label[0][i][0]+1)*(width/2),(label[0][i][1]+1)*(height/2)))
 
	t=time.time()-t1
 
	log.info("grid located in {0:.3}s".format(t))
 
	return points
 

	
 

	
 
if __name__=="__main__":
 
	parser=argparse.ArgumentParser()
 
	parser.add_argument("-i","--input",nargs="+")
 
	parser.add_argument("-o","--output_dir",required=True)
 
	args=parser.parse_args()
 

	
 
	for image_path in args.input:
 
		image=Image.open(image_path)
 
		points=locateGrid(image)
 
		drawer=ImageDraw.Draw(image)
 
		for p in points:
 
			drawer.ellipse((p.x-2,p.y-2,p.x+2,p.y+2),fill="#00ff00")
 
		image.save(os.path.join(args.output_dir,os.path.basename(image_path)))
exp/kerokero/prepare_data.py
Show inline comments
 
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
 
@@ -39,39 +40,57 @@ class Sample:
 
		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 _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):
 
		alpha=random.uniform(0,math.pi*2)
 
		d=random.uniform(0,self.SIDE*0.05)
 
		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()
 
@@ -82,32 +101,33 @@ def traverseDirs(root):
 
		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.POOR: continue
 
		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()
 
			# Sample(np.uint8((transformedImg+1)*128),map(lambda c: (c+EPoint(1,1))*Sample.SIDE/2,transformedGrid)).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()
 
			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)
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,concatenate
 
from keras.models import Sequential,load_model,Model,Input
 
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")
 
@@ -64,59 +64,28 @@ def createCNN():
 

	
 
	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.compile(optimizer="rmsprop",loss=averageDistance,metrics=["mae","accuracy"])
 
	return model
 

	
 

	
 
def createHinted():
 
	input=Input((224,224,1))
 
	base=load_model(args.load_hints)
 
	for layer in base.layers:
 
		layer.trainable=False
 
	hints=base(input)
 

	
 
	x=BatchNormalization()(input)
 
	x=Conv2D(24,(5,5),padding="same",kernel_initializer="he_normal",activation="relu",input_shape=(224,224,1),data_format="channels_last")(x)
 
	x=MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid")(x)
 
	x=Conv2D(36,(5,5),activation="relu")(x)
 
	x=MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid")(x)
 
	x=Conv2D(48,(5,5),activation="relu")(x)
 
	x=MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid")(x)
 
	x=Conv2D(64,(3,3),activation="relu")(x)
 
	x=MaxPooling2D(pool_size=(2,2),strides=(2,2),padding="valid")(x)
 
	x=Conv2D(64,(3,3),activation="relu")(x)
 
	x=GlobalAveragePooling2D()(x)
 

	
 
	x=concatenate([x,Flatten()(hints)])
 
	x=Dense(500,activation="relu")(x)
 
	x=Dense(90,activation="relu")(x)
 

	
 
	predictions=Reshape((4,2))(Dense(8)(x))
 

	
 
	model=Model(inputs=input,outputs=predictions)
 

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

	
 

	
 
if args.load_model:
 
	model=load_model(args.load_model)
 
else:
 
	model=createHinted()
 
	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))
 
	testImages=(np.float32(data["testImages"])/128-1).reshape((-1,224,224,1))
 
	testLabels=data["testLabels"].reshape((-1,4,2))
 
log.info("done")
 

	
 
n=len(trainImages)
 
k=round(n*0.9)
0 comments (0 inline, 0 general)