Skip to content

Commit

Permalink
Improved OCR performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikiforos Archakis committed Oct 10, 2017
1 parent ce06e75 commit 792607a
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 130 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/.gradle
src/main/resources/Outputs/
src/main/resources/Natives/
src/main/resources/OCR/
src/main/resources/OCR/
.idea/
Binary file removed VideoText_Extractor-all.jar
Binary file not shown.
11 changes: 1 addition & 10 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Entities.ApplicationPaths;
import Entities.Controllers;
import Processors.FileProcessor;
import ViewControllers.MainController;
Expand All @@ -9,13 +8,6 @@
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.apache.commons.lang3.SystemUtils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;

import java.lang.reflect.Field;

public class Main extends Application
{
Expand Down Expand Up @@ -44,5 +36,4 @@ public static void main(String[] args) {
launch(args);
}


}
}
11 changes: 5 additions & 6 deletions src/main/java/Processors/FileProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public static boolean createDirectories(File chosenFile)
// Generating unique name of current video file operation
ApplicationPaths.UNIQUE_FOLDER_NAME = chosenFile.getName().replace(".mp4","")+" "+
new Date().toString().replace(":","-");
// Creating paths for application outputs
// Creating directories for application outputs
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,ApplicationPaths.UNIQUE_FOLDER_NAME, "Text Blocks"));
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,"Painted Frames"));
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,ApplicationPaths.UNIQUE_FOLDER_NAME, "Painted Frames"));
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,ApplicationPaths.UNIQUE_FOLDER_NAME, "Steps"));
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,ApplicationPaths.UNIQUE_FOLDER_NAME,"Video"));
Files.createDirectories(Paths.get(ApplicationPaths.RESOURCES_OUTPUTS,ApplicationPaths.UNIQUE_FOLDER_NAME, "OCR Images"));
Expand Down Expand Up @@ -102,8 +102,7 @@ public static File showFileDialog()
/**
* Loads Native Libraries for the detected OS
*/
//TODO load natives cross platform
public static void loadLibraries() throws IOException, URISyntaxException
public static void loadLibraries()
{
setLibraryPath();
try {
Expand Down Expand Up @@ -166,8 +165,8 @@ private static void setLibraryPath() {
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
new Alert(Alert.AlertType.ERROR, "Failed to set JavaLibraryPath!").showAndWait();
Platform.exit();
}
}
}
5 changes: 0 additions & 5 deletions src/main/java/Processors/ImageWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@
import org.opencv.core.MatOfInt;
import org.opencv.imgcodecs.Imgcodecs;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Created by arxa on 26/2/2017.
*/

/**
* This class is used to write and export specific parts of the video processing to
* corresponding application directories
*/
public class ImageWriter
{
private static boolean writingEnabled = false;
Expand Down
123 changes: 40 additions & 83 deletions src/main/java/Processors/OcrProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,117 +2,74 @@

import Entities.ApplicationPaths;
import Entities.Controllers;
import ViewControllers.MainController;
import ViewControllers.SettingsController;
import org.bytedeco.javacpp.BytePointer;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import org.bytedeco.javacpp.tesseract;
import org.jetbrains.annotations.NotNull;
import org.languagetool.JLanguageTool;
import org.languagetool.language.BritishEnglish;
import org.languagetool.rules.RuleMatch;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import static org.bytedeco.javacpp.lept.*;
import static org.bytedeco.javacpp.tesseract.TessBaseAPI;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Created by arxa on 27/4/2017.
*/

public class OcrProcessor
{
private static boolean includeSpecialCharacters;
private static boolean extractUniqueWords;
private static Set<String> uniqueWords;

/**
* Extracts the text representation in the given image, using OCR.
* Depending of the user's selections, certain preprocessing and filtering of the ocr result is applied first
* @param imagePath Path to the input image
* @return The extracted String text
*/
@NotNull
public static String getOcrText(String imagePath) throws IOException, URISyntaxException
{
String selectedLanguage = Controllers.getSettingsController().ocrLanguage_combobox.getSelectionModel().getSelectedItem().toString();
includeSpecialCharacters = Controllers.getSettingsController().includeSpecialCharacters_checkbox.isSelected();
extractUniqueWords = Controllers.getSettingsController().extractUniqueWords_checkbox.isSelected();
BytePointer outText;
TessBaseAPI api = new TessBaseAPI();
private static JLanguageTool languageTool = new JLanguageTool(new BritishEnglish());
private static Pattern pattern = Pattern.compile("[^a-z0-9 ]", Pattern.CASE_INSENSITIVE);

// Setting OCR language
if (api.Init(ApplicationPaths.RESOURCES_OCR, SettingsController.getLanguageMap().get(selectedLanguage)) != 0) {
Controllers.getLogController().logTextArea.appendText("Could not initialize tesseract - ocr!\n");
MainController.getLogStage().show();
public static void initializeOcr(tesseract.TessBaseAPI ocrApi){
if (ocrApi.Init(ApplicationPaths.RESOURCES_OCR, SettingsController.getLanguageMap().
get(Controllers.getSettingsController().ocrLanguage_combobox.getSelectionModel().getSelectedItem().toString())) != 0) {
new Alert(Alert.AlertType.ERROR, "Failed to set OCR language!").showAndWait();
Platform.exit();
}
// if (!Controllers.getSettingsController().includeSpecialCharacters_checkbox.isSelected()){
// ocrApi.SetVariable("tessedit_char_blacklist", "`,#[];()!£\"$%^&\\²³²£§¶¤°¦<>|€");
// }
VideoProcessor.setExtractUniqueWords(Controllers.getSettingsController().extractUniqueWords_checkbox.isSelected());
}

if (!includeSpecialCharacters){
api.SetVariable("tessedit_char_blacklist", "`,#[];()!£\"$%^&\\²³²£§¶¤°¦<>|€");
}

// Open input image with leptonica library
PIX image = pixRead(imagePath);
api.SetImage(image);

// Get OcrProcessor result
outText = api.GetUTF8Text();
if (outText == null) {
Controllers.getLogController().logTextArea.appendText("OcrProcessor Text is NULL - Continuing forward\n");
MainController.getLogStage().show();
api.End();
pixDestroy(image);
return "";
@NotNull
public static String removeSpecialCharacters(String ocrText){
StringBuffer buffer = new StringBuffer(ocrText);
Matcher matcher = pattern.matcher(buffer);
while (matcher.find()){
try {
buffer.replace(matcher.start(), matcher.end(),"");
} catch (StringIndexOutOfBoundsException ignored) {}
matcher = pattern.matcher(buffer);
}
String ocr_text = outText.getString().trim();

// Destroy used object and release memory
api.End();
outText.deallocate();
pixDestroy(image);
return buffer.toString();
}

StringBuffer buffer = new StringBuffer(ocr_text);
JLanguageTool languageTool = new JLanguageTool(new BritishEnglish());
@NotNull
public static String checkForSpelling(String ocrText) {
List<RuleMatch> matches;

// Check for spelling errors and apply suggestion
StringBuffer buffer = new StringBuffer(ocrText);
int iterations = 0;
while (true) {
if (++iterations > 10) break;
matches = languageTool.check(buffer.toString());
if (++iterations > 3) return buffer.toString();
try { matches = languageTool.check(buffer.toString()); }
catch (IOException e) { return ocrText; }
if (!matches.isEmpty()){
if (!matches.get(0).getSuggestedReplacements().isEmpty()){
try {
buffer.replace(matches.get(0).getFromPos(),matches.get(0).getToPos(),matches.get(0).getSuggestedReplacements().get(0));
buffer.replace(matches.get(0).getFromPos(), matches.get(0).getToPos(), matches.get(0).getSuggestedReplacements().get(0));
} catch (StringIndexOutOfBoundsException ignored) {}
} else {
buffer.replace(matches.get(0).getFromPos(),matches.get(0).getToPos(),"");
return " ";
}
} else {
ocr_text = buffer.toString();
break;
return buffer.toString();
}
}

// Check if this word has appeared in the past
if (extractUniqueWords){
if (!uniqueWords.contains(ocr_text)){
uniqueWords.add(ocr_text);
return ocr_text + " ";
}
return "";
}
return ocr_text + " ";
}

public static void initUniqueWords(){
uniqueWords = new TreeSet<>();
}

public static void setIncludeSpecialCharacters(boolean includeSpecialCharacters) {
OcrProcessor.includeSpecialCharacters = includeSpecialCharacters;
}

public static void setExtractUniqueWords(boolean extractUniqueWords) {
OcrProcessor.extractUniqueWords = extractUniqueWords;
}
}
}
Loading

0 comments on commit 792607a

Please sign in to comment.