随着人工智能的发展,让机器代替人的部分工作已成为大趋势。
在教育领域,人工智能也会有发挥的空间,需要指出的是很多人认为人工智能就是完全又机器代替人的工作,实际上当前人工智能的发展还只是在初级阶段,或者说称为弱人工智能。
我们这里就主要讲解在教育领域的弱人工智能应用:
智能问卷系统。
一、应用需求
如何通过系统生成问卷、生成答题卡、自动阅卷功能。
印象中以前我们中考或者高考会用到答题卡,那我们能够在平常每次考试中多用到答题卡么,答案时肯定的,只需要一张A4纸。
二、技术上的需求
我们使用图像处理技术opencv生成问卷、识别答题卡内容。
三、先讲如何生成问卷
/** * 创建答题卡 * * @param path * @param desFile * @param title * @param questionItems * @return * @throws Exception */ public static boolean createAnswerCardImage(String path, String desFile, String title, List<QuestionItem> questionItems) throws Exception { Mat img = Imgcodecs.imread(path); //绘制整体边框线 Imgproc.line(img, new Point(50, 50), new Point(2430, 50), new Scalar(0, 0, 0), 1); Imgproc.line(img, new Point(50, 50), new Point(50, 3458), new Scalar(0, 0, 0), 1); Imgproc.line(img, new Point(2430, 50), new Point(2430, 3458), new Scalar(0, 0, 0), 1); Imgproc.line(img, new Point(50, 3458), new Point(2430, 3458), new Scalar(0, 0, 0), 1); //绘制内容下边框 Imgproc.line(img, new Point(50, 900), new Point(2430, 900), new Scalar(0, 0, 0), 1); //绘制答案及选项 int rowNum = (questionItems.size() % 20 == 0) ? (questionItems.size() / 20) : (questionItems.size() / 20) + 1; int y = 1000; for (int i = 0; i < rowNum; i++) { int x = 60; int optionY = y; for (int j = 0; j < 20; j++) { Imgproc.putText(img, "" + (i * 20 + j + 1), new Point(x, y), Core.FONT_HERSHEY_SCRIPT_COMPLEX, 1, new Scalar(0, 0, 0)); optionY += 100; //绘制4个选项A、B、C、D String[] options = {"[A]", "[B]", "[C]", "[D]"}; for (int z = 1; z <= 4; z++) { String option = options[z - 1]; Imgproc.putText(img, option, new Point(x, optionY), Core.FONT_HERSHEY_DUPLEX, 1, new Scalar(0, 0, 0)); optionY += 100; } x += 100; if ((j + 1) % 4 == 0) x += 100; optionY = y; } y += 500; } Imgcodecs.imwrite(desFile, img); //绘制问卷标题 writeTextToImage("问卷标题", 200, 200, desFile); return true; }
public static void writeTextToImage(String text, int x, int y, String filePath) throws Exception { ImageIcon imgIcon = new ImageIcon(filePath); Image theImg = imgIcon.getImage(); int width = theImg.getWidth(null) == -1 ? 200 : theImg.getWidth(null); int height = theImg.getHeight(null) == -1 ? 200 : theImg.getHeight(null); BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = bimage.createGraphics(); Color mycolor = Color.black; g.setColor(mycolor); g.setBackground(Color.white); g.drawImage(theImg, 0, 0, null); g.setFont(new Font("宋体", Font.PLAIN, 70)); //字体、字型、字号 System.out.println(text); g.drawString(text, x, y); //画文字 g.dispose(); try { FileOutputStream out = new FileOutputStream(filePath); //先用一个特定的输出文件名 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); param.setQuality(100, true); // encoder.encode(bimage, param); out.close(); } catch (Exception e) { throw e; } }
四、如何自动阅卷
public static void recogAnswerCard(String path, List<QuestionItem> questionItems) throws Exception { //装载图片 Mat img = Imgcodecs.imread(path); Mat srcImage2 = new Mat(); Mat srcImage3 = new Mat(); Mat srcImage4 = new Mat(); Mat srcImage5 = new Mat(); //图片变成灰度图片 Imgproc.cvtColor(img, srcImage2, Imgproc.COLOR_RGB2GRAY); //图片二值化 Imgproc.adaptiveThreshold(srcImage2, srcImage3, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 255, 1); //确定腐蚀和膨胀核的大小 Mat element = Imgproc.getStructuringElement(MORPH_RECT, new Size(1, 6)); //腐蚀操作 Imgproc.erode(srcImage3, srcImage4, element); //膨胀操作 Imgproc.dilate(srcImage4, srcImage5, element); //Imgcodecs.imwrite("E:/picpool/bankcard/enresults.jpg", srcImage4); //确定每张答题卡的ROI区域 Mat imag_ch1 = srcImage4.submat(new Rect(50, 900, 2380, 2558)); //识别所有轮廓 Vector<MatOfPoint> chapter1 = new Vector<>(); Imgproc.findContours(imag_ch1, chapter1, new Mat(), 2, 3); Mat result = new Mat(imag_ch1.size(), CV_8U, new Scalar(255)); Imgproc.drawContours(result, chapter1, -1, new Scalar(0), 2); Imgcodecs.imwrite("D://opencv//result.jpg", result); //new一个 矩形集合 用来装 轮廓 List<answercard.RectComp> RectCompList = new ArrayList<>(); for (int i = 0; i < chapter1.size(); i++) { Rect rm = Imgproc.boundingRect(chapter1.get(i)); answercard.RectComp ti = new answercard.RectComp(rm); //把轮廓宽度区间在 50 - 80 范围内的轮廓装进矩形集合 if (ti.rm.width > 50 && ti.rm.width < 100) { RectCompList.add(ti); } } //new一个 map 用来存储答题卡上填的答案 (A\B\C\D) TreeMap<Integer, String> listenAnswer = new TreeMap<>(); //按 X轴 对listenAnswer进行排序 RectCompList.sort((o1, o2) -> { if (o1.rm.x > o2.rm.x) { return 1; } if (o1.rm.x == o2.rm.x) { return 0; } if (o1.rm.x < o2.rm.x) { return -1; } return -1; }); /* 如果精度高,可以通过像素计算 for (RectComp rc : RectCompList) { int x = RectCompList.get(t).getRm().x - 16; int y = RectCompList.get(t).getRm().y - 94; //计算x轴上的分割 如果超过5题,那么还会有一个大分割 int xSplit = x/85 /5; //因为第一题 x=21 计算机中题目从0开始算,现实是从1开始 所以+1 int xTitleNum = x/85 + 1; //由于精度问题 x轴会慢慢递减 递减到上一个答案去 如果不跨过两个答案以上,都没问题 如果答题卡x轴40题左右 会出问题 if(x%85>20){ System.out.println("x轴递减程度" + x%85); xTitleNum++; } xTitleNum = xTitleNum - xSplit; System.out.println(xTitleNum); } */ //根据 Y轴 确定被选择答案 (A\B\C\D) for (answercard.RectComp rc : RectCompList) { for (int h = 0; h < 5; h++) { if ((RectUtil.rectContainRect(new Rect(0, 100 + 500 * h, 2380, 100), rc.rm, 30))) { int x=0; for (int j = 0; j < 20; j++) { if ((RectUtil.rectContainPoint(new Rect(x, 100 + 500 * h, 100, 100), new Point(rc.rm.x+rc.rm.width/2,rc.rm.y+rc.rm.height/2)))) { listenAnswer.put(h*20+j+1,"C"); break; } x += 100; if ((j + 1) % 4 == 0) x += 100; } } else if ((RectUtil.rectContainRect(new Rect(0, 200 + 500 * h, 2380, 100), rc.rm, 30))) { int x=0; for (int j = 0; j < 20; j++) { if ((RectUtil.rectContainPoint(new Rect(x, 200 + 500 * h, 100, 100), new Point(rc.rm.x+rc.rm.width/2,rc.rm.y+rc.rm.height/2)))) { listenAnswer.put(h*20+j+1,"C"); break; } x += 100; if ((j + 1) % 4 == 0) x += 100; } } else if ((RectUtil.rectContainRect(new Rect(0, 300 + 500 * h, 2380, 100), rc.rm, 30))) { int x=0; for (int j = 0; j < 20; j++) { if ((RectUtil.rectContainPoint(new Rect(x, 300 + 500 * h, 100, 100), new Point(rc.rm.x+rc.rm.width/2,rc.rm.y+rc.rm.height/2)))) { listenAnswer.put(h*20+j+1,"C"); break; } x += 100; if ((j + 1) % 4 == 0) x += 100; } } else if ((RectUtil.rectContainRect(new Rect(0, 400 + 500 * h, 2380, 100), rc.rm, 30))) { int x=0; for (int j = 0; j < 20; j++) { if ((RectUtil.rectContainPoint(new Rect(x,400 + 500 * h, 100, 100), new Point(rc.rm.x+rc.rm.width/2,rc.rm.y+rc.rm.height/2)))) { listenAnswer.put(h*20+j+1,"C"); break; } x += 100; if ((j + 1) % 4 == 0) x += 100; } } } } Iterator iter = listenAnswer.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object val = entry.getValue(); System.out.println("第" + key + "题,分数:" + val); } }
版权声明:本文为luobanggreat原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。