【為生活開發系列之四】圖片文字識別與標準文件對比工具

Roll圈圈發表於2018-03-08

前言

我:測試?測試?測試? 5s後 測試:剛剛在對比網頁上圖片上的文字和標準文件裡面的文字是不是一樣的,看的老孃眼都廢了,沒空理你。 我:。。。。。。這麼low的嗎? 測試:莫非這位兄臺有高見? 我:稍等。。。好了,可以了,來試試? 。。。 測試:666

效果預覽

效果預覽

目標需求與實現需求的思路

由於每次上線活動或者運營報告的時候,網頁上的很多內容直接就是UI弄好的圖片,UI將圖片給前端,前端直接顯示這些圖片,但是UI在製作這些圖片的時候可能複製錯內容,所以測試需要在每次上下前檢查這些內容是否正確,原始的做法是電腦左邊顯示網頁,右邊顯示標準文件,一個字一個字的檢查,這種方式不僅慢,效率低而且容易出錯,所以需要我們的時候到了。

需求:

給定需要檢查的圖片,識別圖片上的內容,然後與標準文件裡面的內容進行比較,找出錯別字,提交給前端和UI設計師修改。為了互動友好,我們需要做一個視覺化介面進行操作。由於圖片的識別可能會出錯,所以我們需要在介面上實時的顯示出被檢測的圖片,然後在對比出錯的時候檢查圖片識別是否出問題了。

就拿上面的例子來說明,我們識別的標準文件在最上面,目標標準內容是上面輸入內容去掉所有的標點符號和空格後的內容,識別圖片內容是識別的圖片上的內容,在我們第一次點選開始比較的時候,顯示的是匹配不成功,我們拖動進度條之後發現,標準內容比我們識別出來的內容多一個“平”字,我們檢查下面的圖片後發現,這個“平”字是存在的,只是識別的時候出現了問題,那麼我們就認為這個不算錯誤,我們刪掉目標內容中的“平”字,然後再一次進行比較,此時顯示對比成功,那麼我們認為這個圖片中的內容與標準文件中的內容是一致的。雖然也還是存在一些誤差,但是這中方式的效率的正確率已經是之前那種方式的好幾倍了。^_^

實現需求的思路

核心功能是圖片的識別,之前瞭解到百度雲下有一個技術是圖片文字識別的技術,正好可以派上用場了。 百度雲文字識別快速入門,連結是 https://cloud.baidu.com/doc/OCR/OCR-Java-SDK.html#.E5.BF.AB.E9.80.9F.E5.85.A5.E9.97.A8,用法很簡單,首先註冊賬號,獲取對應的key,secret和id啥的,然後免費版的一天可以最多識別圖片500次,對於我們測試來說,足矣。

其次,識別出圖片上的文字之後,我們需要將識別出的文字去掉所有空格和標點符號備用A1,獲取標準內容後去掉所有空格和標點符號備用A2,然後比較A1和A2,如果是一樣的就表示匹配成功,如果不一樣,我們監聽識別圖片內容的文字框的滑動條B2,在我們滑動這個滑動條的時候,動態的去滑動目標標準內容的滑動條B1,這樣的目的是為了方便的找出不一致的文字所在的地方,找到地方之後,判斷是識別問題還是真的有問題,再做相應的處理即可。

程式碼實現

由於時間比較緊,所以有些處理不是很好,以後有時間了再優化,比如去除空格和標符號的處理,就相當low逼,大家忍忍吧。

package com.cretin;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.json.JSONArray;
import org.json.JSONObject;

import com.baidu.aip.ocr.AipOcr;

/**
 * <p>
 * Title: TupianShibie
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Company: www.cretin.com
 * </p>
 * 
 * @author cretin
 * @date 2018年2月2日
 */
public class TupianShibie extends JFrame {
	private static final long serialVersionUID = 1L;
	// 設定APPID/AK/SK
	public static final String APP_ID = "YOUR APP_ID";
	public static final String API_KEY = "YOUR API_KEY";
	public static final String SECRET_KEY = "YOUR SECRET_KEY";

	// 設定寬高
	private static int mWidth = 1000;
	private static int mHeight = 800;

	// 當前選擇的檔案
	private String currFilePath = "";

	// 控制元件
	private JPanel mainPanel;

	public TupianShibie() {
		setTitle("圖片識別與文字對比助手");

		// 獲取螢幕寬度
		Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
		mWidth = (int) ((int) screensize.getWidth() * 0.9);
		mHeight = (int) ((int) screensize.getHeight() * 0.9);
		setSize(mWidth, mHeight);
		setResizable(false);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		mainPanel = new JPanel();
		mainPanel.setLayout(null);

		// 標準內容區域
		JLabel label1 = new JLabel("請輸入標準內容");
		label1.setBounds(10, 20, 100, 20);
		mainPanel.add(label1);
		JTextArea textArea = new JTextArea();
		textArea.setLineWrap(true);// 設定文字區的換行策略
//      測試時使用 免得每次都輸入內容
//		textArea.setText(
//				"新春佳節過後,永珍更新,人們飽含著新的希望朝著新的目標,整裝待發、再啟征程。狗年伊始,網貸行業的發展現狀是怎麼樣的?房融界又有哪些規劃呢?2018網貸備案年正式開啟,隨著監管政策一步一步的落實,各網貸平臺加速合規,全力迎接4月份的終極“大考”。同時,在備案關鍵期,平臺對資產資質稽核也將越來越嚴格,投資人將面臨繼年關過後的又一段“投標荒”時期。\n"
//						+ "		順利完成備案登記將是房融界接下來工作的重中之重。2018年1月份,房融界已經向前海管理局提交了全部自查資料,並遵循政策的指引,根據律所和會計所出具的建議書加速合規整改,力爭今年備案成功。同時,為解決當前投資人搶標困難的情況,房融界已經對接了車貸、消費分期等符合監管規定的優質的資產,並計劃於近期上線。進行合規建設的同時,房融界也一直不敢放鬆對風控體系和使用者體驗的打造,今年房融界會繼續借助科技的力量完善風控、打磨產品,提升平臺服務品質。厚積“搏8”,“犬力”以赴。2018,房融界將在合規的路上繼續砥礪前行,努力為投資人構建更安全、更可靠的投資環境。");
		JScrollPane jsp0 = new JScrollPane(textArea);
		jsp0.setBounds(116, 10, mWidth - 10 - 120 - 100, 100);
		jsp0.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		mainPanel.add(jsp0);

		// 兩個按鈕
		JButton jButton1 = new JButton("開啟圖片");
		JButton jButton2 = new JButton("開始比較");
		JButton jButton3 = new JButton("清空資料");
		jButton1.setBounds(mWidth - 100, 15, 90, 30);
		jButton2.setBounds(mWidth - 100, 45, 90, 30);
		jButton3.setBounds(mWidth - 100, 75, 90, 30);
		mainPanel.add(jButton1);
		mainPanel.add(jButton2);
		mainPanel.add(jButton3);
		add(mainPanel);

		// 目標標準內容
		JLabel label2 = new JLabel("目標標準內容");
		label2.setBounds(10, 130, 100, 20);
		JTextField jTextField = new JTextField();
		JScrollPane jsp = new JScrollPane(jTextField);
		jsp.setBounds(116, 120, mWidth - 10 - 120, 60);
		jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		jsp.getHorizontalScrollBar().setEnabled(false);
		mainPanel.add(label2);
		mainPanel.add(jsp);

		// 識別圖片內容
		JLabel label3 = new JLabel("識別圖片內容");
		label3.setBounds(10, 200, 100, 20);
		JTextField jTextField1 = new JTextField();
		jTextField1.setEditable(false);
		JScrollPane jsp1 = new JScrollPane(jTextField1);
		jsp1.setBounds(116, 190, mWidth - 10 - 120, 60);
		jsp1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		mainPanel.add(label3);
		mainPanel.add(jsp1);

		// 所選圖片預覽
		JLabel label4 = new JLabel("所選圖片預覽");
		label4.setBounds(10, 270, 100, 20);
		mainPanel.add(label4);
		JLabel label = new JLabel();
		JScrollPane jsp2 = new JScrollPane(label);
		int picHeight = mHeight - 260;
		jsp2.setBounds(116, 260, mWidth - 20 - 110, picHeight - 130);
		mainPanel.add(jsp2);

		// 對比結果預覽
		JLabel label5 = new JLabel("操作控制檯");
		label5.setBounds(10, 270 + picHeight - 130 + 10, 100, 20);
		mainPanel.add(label5);
		JTextArea textArea1 = new JTextArea();
		JScrollPane jsp3 = new JScrollPane(textArea1);
		jsp3.setBounds(116, 260 + picHeight - 130 + 10, mWidth - 20 - 110, mHeight - (260 + picHeight - 130 + 10 + 30));
		jsp3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		mainPanel.add(jsp3);

		add(mainPanel);

		// 新增事件
		// 選擇資料夾
		jButton1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// 檢查內容
				String tag = textArea.getText();
				if (tag == null || tag.equals("")) {
					JOptionPane.showMessageDialog(getContentPane(), "請先輸入標準內容再操作", "系統資訊", JOptionPane.WARNING_MESSAGE);
					return;
				}
				JFileChooser jfc = new JFileChooser();
				jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
				jfc.showDialog(new JLabel(), "選擇資料夾");
				File file = jfc.getSelectedFile();
				if (file != null) {
					textArea1.append("已選擇檔案:" + file.getAbsolutePath() + "\n");
					ImageIcon img = new ImageIcon(file.getAbsolutePath());// 建立圖片物件
					label.setIcon(img);
					currFilePath = file.getAbsolutePath();
				} else {
					textArea1.append("取消選擇檔案......\n");
				}
			}
		});

		// 開始對比
		jButton2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (currFilePath != "" && !currFilePath.equals("")) {
					String tag = textArea.getText();
					doInt(tag, currFilePath, textArea1, jTextField, jTextField1,jButton2);
				} else {
					JOptionPane.showMessageDialog(getContentPane(), "請先選擇圖片再操作", "系統資訊", JOptionPane.WARNING_MESSAGE);
				}
			}
		});
        //清空資料
		jButton3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// 清空所有資料
				textArea1.append("清空所有資料,準備進行下一次操作!!!\n");
				jTextField.setText("");
				jTextField1.setText("");
				textArea.setText("");
				//清空圖片
				label.setIcon(null);
				currFilePath = "";
				jButton2.setEnabled(true);
			}
		});
		// 對滑動條進行監聽
		JScrollBar bar = jsp1.getHorizontalScrollBar();
		bar.addAdjustmentListener(new AdjustmentListener() {

			@Override
			public void adjustmentValueChanged(AdjustmentEvent e) {
                //獲取到標準內容的滑動條 並將目前滑動的進度傳給他
				jsp.getHorizontalScrollBar().setValue(e.getValue());
			}
		});
		// 顯示窗體
		setVisible(true);
	}

	public static void main(String[] args) {
		new TupianShibie();
	}

	private void doInt(String aimStr, String path, JTextArea textArea1, 
			JTextField jTextField, JTextField jTextField1, JButton jButton2) {
		String aimStr1 = "";
		String content = jTextField.getText();
		if (content == "" || content.equals("")) {
			aimStr1 = formatStr(aimStr);
			jTextField.setText(aimStr1);
		}else {
			aimStr1 = content;
		}
		final String aimStr2 = aimStr1;
		jButton2.setEnabled(false);
		textArea1.append("正在對比,請等待...\n");
		// 初始化一個AipOcr
		AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
		// 可選:設定網路連線引數
		client.setConnectionTimeoutInMillis(2000);
		client.setSocketTimeoutInMillis(60000);
		new Thread() {
			public void run() {
				// 呼叫介面
				JSONObject res = client.basicGeneral(path, new HashMap<String, String>());
				JSONArray array = res.getJSONArray("words_result");
				Iterator<Object> it = array.iterator();
				StringBuffer stringBuffer = new StringBuffer();
				while (it.hasNext()) {
					JSONObject ob = (JSONObject) it.next();
					String ss = ob.getString("words");
					stringBuffer.append(ss);
				}
				String endStr = formatStr(stringBuffer.toString());
				jTextField1.setText(endStr);
				textArea1.append("對比完成!!!\n");
				if (endStr.equals(aimStr2)) {
					textArea1.append("對比結果:匹配成功\n");
					JOptionPane.showMessageDialog(getContentPane(), "恭喜,匹配成功", "系統資訊", JOptionPane.INFORMATION_MESSAGE);
				} else {
					textArea1.append("對比結果:匹配不成功,請檢查\n");
					JOptionPane.showMessageDialog(getContentPane(), "匹配不成功,請注意", "系統資訊", JOptionPane.WARNING_MESSAGE);
				}
				jButton2.setEnabled(true);
			};
		}.start();

	}

	// 去除標點符號 去除換行和空格
	private static String formatStr(String aimStr) {
		aimStr = aimStr.trim();
		// 對aimStr 去除標點符號 去除換行和空格
		aimStr = aimStr.replaceAll("\\n", "");
		aimStr = aimStr.replaceAll("\\r", "");
		aimStr = aimStr.replaceAll("\\t", "");
		aimStr = aimStr.replaceAll(",", "");
		aimStr = aimStr.replaceAll("。", "");
		aimStr = aimStr.replaceAll(",", "");
		aimStr = aimStr.replaceAll("、", "");
		aimStr = aimStr.replaceAll("\\.", "");
		aimStr = aimStr.replaceAll("(", "");
		aimStr = aimStr.replaceAll(")", "");
		aimStr = aimStr.replaceAll("\\)", "");
		aimStr = aimStr.replaceAll("\\(", "");
		aimStr = aimStr.replaceAll("!", "");
		aimStr = aimStr.replaceAll("!", "");
		aimStr = aimStr.replaceAll("\\?", "");
		aimStr = aimStr.replaceAll("?", "");
		aimStr = aimStr.replaceAll("“", "");
		aimStr = aimStr.replaceAll("\\:", "");
		aimStr = aimStr.replaceAll(":", "");
		aimStr = aimStr.replaceAll(";", "");
		aimStr = aimStr.replaceAll("\\;", "");
		aimStr = aimStr.replaceAll("”", "");
		aimStr = aimStr.replaceAll("\"", "");
		aimStr = aimStr.replaceAll(" ", "");
		return aimStr;
	}
}
複製程式碼

相關連線

百度雲文字識別快速入門,連結是 https://cloud.baidu.com/doc/OCR/OCR-Java-SDK.html#.E5.BF.AB.E9.80.9F.E5.85.A5.E9.97.A8

百度雲文字識別sdk下載,連結是 http://ai.baidu.com/sdk

GIthub專案QuickMapping,連結是 https://github.com/MZCretin/QuickMapping

本專案程式碼也已經上傳github了,可以直接使用專案中的jar檔案,另外大家需要自己去申請賬號哦,為了測試能正常使用,我的賬號就不暴露了,謝謝理解。

我就是比較喜歡用程式碼解決生活中的問題,感覺很開心,哈哈哈。也喜歡大家關注我的簡書,掘金,Github和CSDN。

簡書首頁,連結是 https://www.jianshu.com/u/123f97613b86

掘金首頁,連結是 https://juejin.im/user/5838d57fac502e006c1708bc

Github首頁,連結是 https://github.com/MZCretin

CSDN首頁,連結是 http://blog.csdn.net/u010998327

我是Cretin,一個可愛的小男孩。

相關文章