ฉันทำงานเกี่ยวกับการรับรู้ด้วยตัวเลขหลายหลักด้วยมือJava
โดยใช้OpenCV
ห้องสมุดสำหรับการประมวลผลล่วงหน้าและการแบ่งส่วนและKeras
รูปแบบการฝึกอบรมเกี่ยวกับ MNIST (ด้วยความแม่นยำ 0.98) สำหรับการรับรู้
การรับรู้ดูเหมือนจะทำงานได้ค่อนข้างดีนอกเหนือจากสิ่งหนึ่ง เครือข่ายค่อนข้างบ่อยครั้งที่จะจำสิ่งที่ไม่ได้ (หมายเลข "หนึ่ง") ฉันไม่สามารถทราบได้ว่าเกิดขึ้นเนื่องจากการดำเนินการแบ่งเซกเมนต์ล่วงหน้า / ไม่ถูกต้องหรือหากเครือข่ายที่ได้รับการฝึกอบรมเกี่ยวกับ MNIST มาตรฐานเพิ่งไม่เห็นหมายเลขหนึ่งซึ่งดูเหมือนว่ากรณีทดสอบของฉัน
นี่คือสิ่งที่ตัวเลขที่เป็นปัญหามีลักษณะเหมือนหลังการประมวลผลล่วงหน้าและการแบ่งส่วน:
กลายเป็นและจัดเป็น 4
และอื่น ๆ ...
นี่เป็นสิ่งที่สามารถแก้ไขได้โดยการปรับปรุงกระบวนการแบ่งส่วนหรือไม่ หรือโดยการเพิ่มชุดฝึกอบรม
แก้ไข: การปรับปรุงชุดฝึกอบรม (การเพิ่มข้อมูล) จะช่วยได้อย่างแน่นอนซึ่งฉันได้ทำการทดสอบแล้วคำถามของการประมวลผลที่ถูกต้องยังคงอยู่
การประมวลผลล่วงหน้าของฉันประกอบด้วยการปรับขนาดการแปลงเป็นโทนสีเทาการแปลงแบบสองทางการหมุนและการขยาย นี่คือรหัส:
Mat resized = new Mat();
Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);
Mat grayscale = new Mat();
Imgproc.cvtColor(resized, grayscale, Imgproc.COLOR_BGR2GRAY);
Mat binImg = new Mat(grayscale.size(), CvType.CV_8U);
Imgproc.threshold(grayscale, binImg, 0, 255, Imgproc.THRESH_OTSU);
Mat inverted = new Mat();
Core.bitwise_not(binImg, inverted);
Mat dilated = new Mat(inverted.size(), CvType.CV_8U);
int dilation_size = 5;
Mat kernel = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_CROSS, new Size(dilation_size, dilation_size));
Imgproc.dilate(inverted, dilated, kernel, new Point(-1,-1), 1);
อิมเมจที่ถูกประมวลผลล่วงหน้าจะถูกแบ่งเป็นตัวเลขแต่ละตัวดังต่อไปนี้:
List<Mat> digits = new ArrayList<>();
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(preprocessed.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// code to sort contours
// code to check that contour is a valid char
List rects = new ArrayList<>();
for (MatOfPoint contour : contours) {
Rect boundingBox = Imgproc.boundingRect(contour);
Rect rectCrop = new Rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);
rects.add(rectCrop);
}
for (int i = 0; i < rects.size(); i++) {
Rect x = (Rect) rects.get(i);
Mat digit = new Mat(preprocessed, x);
int border = 50;
Mat result = digit.clone();
Core.copyMakeBorder(result, result, border, border, border, border, Core.BORDER_CONSTANT, new Scalar(0, 0, 0));
Imgproc.resize(result, result, new Size(28, 28));
digits.add(result);
}