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__":
 
@@ -40,10 +41,13 @@ if __name__=="__main__":
 
	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
 
@@ -10,10 +10,11 @@ with open(os.path.join(thisDir,"config.j
 
	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
 

	
 
@@ -45,12 +46,25 @@ class Sample:
 
		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)
 

	
 
@@ -60,12 +74,17 @@ class Sample:
 
		(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)
 
@@ -88,20 +107,21 @@ def harvestDir(path):
 
	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
exp/kerokero/train.py
Show inline comments
 
@@ -2,14 +2,14 @@ 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
 

	
 
@@ -70,47 +70,16 @@ def createCNN():
 
	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))
0 comments (0 inline, 0 general)