diff --git a/exp/annotations.py b/exp/annotations.py
--- a/exp/annotations.py
+++ b/exp/annotations.py
@@ -10,12 +10,22 @@ from analyzer.corners import Corners
 
 
 class Board:
+	labels=["UNSET","CLEAR","GOOD","POOR"]
+	UNSET=0
+	CLEAR=1
+	GOOD=2
+	POOR=3
+
 	def __init__(self,**kwargs):
 		self.board=Corners(kwargs.get("board") or [])
 		self.grid=Corners(kwargs.get("grid") or [])
+		self.grade=kwargs.get("grade") or Board.UNSET
 
 	def isEmpty(self):
-		return len(self.board)==0 and len(self.grid)==0
+		return len(self.board)==0 and len(self.grid)==0 and self.grade==Board.UNSET
+
+	def setGrade(self,g):
+		self.grade=g
 
 
 class DataFile(MutableMapping):
@@ -36,7 +46,7 @@ class DataFile(MutableMapping):
 		if isinstance(obj,EPoint):
 			return {"type": "EPoint", "val": [obj.x,obj.y]}
 		elif isinstance(obj,Board):
-			return {"type": "Board", "val": {"board": list(obj.board), "grid": list(obj.grid)}}
+			return {"type": "Board", "val": {"board": list(obj.board), "grid": list(obj.grid), "grade": obj.grade}}
 		raise TypeError(obj)
 
 	def deserialize(self,obj):
diff --git a/exp/color_sampler.py b/exp/color_sampler.py
--- a/exp/color_sampler.py
+++ b/exp/color_sampler.py
@@ -94,15 +94,21 @@ class Sampler:
 	def deleteBoard(self):
 		self._boards.pop(self.m)
 		self._flush()
-		self._dirty=True
 		self.showImage()
 
 	def addCorner(self,e):
 		self.corners.add(e.x,e.y)
 		self._flush()
-		self._dirty=True
 		self._markCorners()
 
+	def setGrade(self,g):
+		self.board.setGrade(g)
+		self._flush()
+		if len([b for b in self._boards if not b.isEmpty()])>1:
+			self.switchCorners(1)
+		else:
+			self.switchImage(1)
+
 	def save(self):
 		if self._dirty:
 			self.annotations.save()
@@ -110,6 +116,7 @@ class Sampler:
 
 	def _flush(self):
 		self.annotations[self.filename]=[b for b in self._boards if not b.isEmpty()]
+		self._dirty=True
 
 	def _createGUI(self):
 		self.root=root=tk.Tk()
@@ -137,6 +144,9 @@ class Sampler:
 		root.bind("<Key-period>",lambda e: self.switchAsterisk())
 		root.bind("<Key-comma>",lambda e: self.switchGrid())
 		root.bind("<d>",lambda e: self.deleteBoard())
+		root.bind("<Key-1>",lambda e: self.setGrade(Board.CLEAR))
+		root.bind("<Key-2>",lambda e: self.setGrade(Board.GOOD))
+		root.bind("<Key-3>",lambda e: self.setGrade(Board.POOR))
 
 		root.mainloop()
 
@@ -150,6 +160,8 @@ class Sampler:
 		self.colorLabel.pack(side=LEFT)
 		self.asteriskLabel=tk.Label(bar,width=4,text="()")
 		self.asteriskLabel.pack(side=LEFT)
+		self.gradeLabel=tk.Label(bar,width=8,text="")
+		self.gradeLabel.pack(side=LEFT)
 
 		return bar
 
@@ -167,10 +179,15 @@ class Sampler:
 					self.canvas.create_line(b.x,b.y,c.x,c.y,fill="#00ff00",dash=dash,tags="mark")
 					self.canvas.create_line(c.x,c.y,d.x,d.y,fill="#00ff00",dash=dash,tags="mark")
 					self.canvas.create_line(d.x,d.y,a.x,a.y,fill="#00ff00",dash=dash,tags="mark")
+		self.gradeLabel.configure(text=Board.labels[self.board.grade])
+
+	@property
+	def board(self):
+		return self._boards[self.m]
 
 	@property
 	def corners(self):
-		b=self._boards[self.m]
+		b=self.board
 		return b.grid if self.isGrid else b.board
 
 	@property
diff --git a/exp/kerokero/prepare_data.py b/exp/kerokero/prepare_data.py
--- a/exp/kerokero/prepare_data.py
+++ b/exp/kerokero/prepare_data.py
@@ -2,19 +2,25 @@ import os
 import sys
 import re
 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
+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
 
@@ -61,6 +67,7 @@ class Sample:
 		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)
 
 
@@ -70,7 +77,7 @@ def traverseDirs(root):
 		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):
-			print(d)
+			log.info(d)
 			yield d
 		for f in contents:
 			if f.is_dir(): stack.append(f.path)
@@ -82,6 +89,9 @@ def harvestDir(path):
 	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
 		img=cv.imread(f.path)
 		img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
 		for b in boards:
@@ -101,6 +111,11 @@ def loadDataset(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)