一则比较有意思的应用,来自斯坦福 EE368/CS232:Digital Image Processing 课程作业1
【另外,推荐大家去看看老外的课程设计,全是图像处理+android / ios,有题目,有代码,有说明,有海报及视频展示】
原文:
Automatic Quiz Grading
On the handouts webpage, you can find three scanned images of a multiple-choice quiz for an introductory algebra class:
. hw1_quiz_solution.jpg: official solution for the quiz created by the instructor
. hw1_quiz_student_1.jpg: responses given by student #1 in the class
. hw1_quiz_student_2.jpg: responses given by student #2 in the class
Develop and describe the steps for an image processing algorithm that automatically computes the number of wrong answers for each student. Show any intermediate images produced in the algorithm to help explain the individual steps. Report the number of wrong answers for student #1 and student #2 as determined by your algorithm. You can exploit the fact that each circle used in a multiple-choice question covers approximately 85 pixels in these scanned images.
大致翻译:
自动答题卡评卷【涂圆圈的】,有3张图片,一张为标准答案hw1_quiz_solution.jpg,两张学生答卷:hw1_quiz_student_1.jpg和hw1_quiz_student_2.jpg,现在要通过图像处理的方式,自动评卷。这里 ,答题填涂的圆圈像素大致为85
标准答案:
学生答卷1:
学生答卷2:
解决方案【我不贴英文了】
1.观察答卷发现,试卷的抬头和标题不是我们想关注的,因此舍弃图像的前17%,设置我们的ROI【感兴趣区域】
2.为了实现学生答卷和标准答案之间的配准:在水平和垂直方向,通过小范围偏移,使得均方误差最小【对准了试卷,再比较圆圈】
3.从标准答卷中减去学生答卷,计算差分图像
4.阈值化差分图像,统计大于阈值的像素个数,除以85,再除以2,即为错误答案个数
【这边除以2是因为当一题答错时,一定是这样:该涂黑的地方,没涂黑;该留白的地方,涂了黑。而差分图像计算了2次差异,故除以2】--- 我想了10分钟才弄明白,太笨了
另外,老外为了展示图像配准的重要性,故意弄了个对比实验:a.未配准,直接计算差分+统计;b.配准后,计算差分+统计
matlab实现:
clc; clear all; % Load solution image imgSolution = im2double(imread('hw1_quiz_solution.jpg')); [height, width] = size(imgSolution); rowsROI = round(0.17*height):height; imgSolution = imgSolution(rowsROI, :); [height, width] = size(imgSolution); % Define parameters circleArea = 85; threshold = 0.8; % Load test image %imgTest = im2double(imread('hw1_quiz_student_1.jpg')); imgTest = im2double(imread('hw1_quiz_student_2.jpg')); imgTest = imgTest(rowsROI, :); % Estimate number of wrong answers without alignment imgDiffUnalign = abs(imgTest - imgSolution); imgDiffUnalignThresh = imgDiffUnalign > threshold; numDiffUnalign = sum(imgDiffUnalignThresh(:)) / circleArea; numWrongUnalign = numDiffUnalign / 2 % Perform alignment minSSE = inf; for dx = -1 : 0.25 : 1 for dy = -2 : 0.25 : 2 A = [1 0 dx; 0 1 dy; 0 0 1]; tform = maketform('affine', A.'); imgTform = imtransform(imgTest, tform, 'bilinear', ... 'XData', [1 width], 'YData', [1 height], ... 'FillValues', 1); imgSSE = sum(sum((imgTform - imgSolution).^2)); if imgSSE < minSSE minSSE = imgSSE; imgTestAlign = imgTform; bestDx = dx; bestDy = dy; end end % dy end % dx disp(sprintf('Best dx = %.2f, dy = %.2f', bestDx, bestDy)); % Estimate number of wrong answers with alignment imgDiffAlign = abs(imgTestAlign - imgSolution); imgDiffAlignThresh = imgDiffAlign > threshold; numDiffAlign = sum(imgDiffAlignThresh(:)) / circleArea; numWrongAlign = numDiffAlign / 2 % Show images warning off; figure(1); clf; set(gcf, 'Color', 'w'); imshow(imgDiffUnalign,[0 1]); colorbar; title('Difference without Alignment'); figure(2); clf; set(gcf, 'Color', 'w'); imshow(imgDiffUnalignThresh); title('Difference without Alignment - Thresholded'); figure(3); clf; set(gcf, 'Color', 'w'); imshow(imgDiffAlign,[0 1]); colorbar; title('Difference with Alignment'); figure(4); clf; set(gcf, 'Color', 'w'); imshow(imgDiffAlignThresh); title('Difference with Alignment - Thresholded');
实验结果
学生答卷1:
未配准差分图像:
阈值化未配准差分图像:
配准后差分图像:
阈值化配准后差分图像:
Paper1的控制台结果:
学生答卷2:
配准后差分图像:
阈值化配准后差分图像:
Paper2 控制台结果:
由于提到了图像配准,这里 附上仿射变换矩阵的原理图:
仿射变换是一种常用矩阵变换,二维图像的仿射变换可以表示成如下矩阵的形式:
这里(w,z)为原始坐标,(x,y)为新坐标。
由于拍摄答卷时,或多或少有偏移,因此在计算图像差分前,应该先进行配准。如果在本次应用中只考虑旋转和平移,则仿射变换矩阵为:
而老外的代码中,theta设为0,仅仅从水平和垂直方向去搜索,使得均方差最小。
接下来是一些matlab语言类的处理,比如构造TFORM结构体和imtransform函数的使用,大家自己查帮助文档吧。
Happy Valentine's Day!