0xbad1d3a5 / Kaku

画 - Japanese OCR Dictionary
https://kaku.fuwafuwa.ca/
BSD 3-Clause "New" or "Revised" License
203 stars 36 forks source link

Kaku crashes when no kanji is detected by the OCR engine #3

Closed 0xbad1d3a5 closed 7 years ago

0xbad1d3a5 commented 7 years ago

LOG:

01-13 15:12:07.001 23231 23231 D ca.fuwafuwa.kaku.Ocr.OcrRunnable: NOTIFIED
01-13 15:12:07.002 23231 23258 D ca.fuwafuwa.kaku.Ocr.OcrRunnable: THREAD STOPPED WAITING
01-13 15:12:07.002 23231 23258 D ca.fuwafuwa.kaku.Ocr.OcrRunnable: X:1040 Y:1176 (267x129)
01-13 15:12:07.008 23231 23258 D ca.fuwafuwa.kaku.Ocr.OcrRunnable: Image Dimensions: 2560x1440
01-13 15:12:07.084 23231 23258 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 23258 (Thread-4)
01-13 15:12:07.084   256   256 W         : debuggerd: handling request: pid=23231 uid=10149 gid=10149 tid=23258
01-13 15:12:07.088 23330 23330 W debuggerd: type=1400 audit(0.0:576): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.088 23330 23330 W debuggerd: type=1400 audit(0.0:577): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.088 23330 23330 W debuggerd: type=1400 audit(0.0:578): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:579): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:580): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:581): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:582): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:583): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.095 23330 23330 W debuggerd: type=1400 audit(0.0:584): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:585): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:586): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:587): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:588): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:589): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:590): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:591): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:592): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:593): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:594): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:595): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:596): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:597): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:598): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.098 23330 23330 W debuggerd: type=1400 audit(0.0:599): avc: denied { search } for name="ca.fuwafuwa.kaku" dev="mmcblk0p42" ino=432919 scontext=u:r:debuggerd:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0
01-13 15:12:07.119 23330 23330 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-13 15:12:07.119 23330 23330 F DEBUG   : Build fingerprint: 'google/shamu/shamu:7.0/NBD91J/3318369:user/release-keys'
01-13 15:12:07.119 23330 23330 F DEBUG   : Revision: '0'
01-13 15:12:07.119 23330 23330 F DEBUG   : ABI: 'arm'
01-13 15:12:07.119 23330 23330 F DEBUG   : pid: 23231, tid: 23258, name: Thread-4  >>> ca.fuwafuwa.kaku <<<
01-13 15:12:07.119 23330 23330 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
01-13 15:12:07.119 23330 23330 F DEBUG   :     r0 00000000  r1 00005ada  r2 00000006  r3 00000008
01-13 15:12:07.119 23330 23330 F DEBUG   :     r4 8e0ff978  r5 00000006  r6 8e0ff920  r7 0000010c
01-13 15:12:07.119 23330 23330 F DEBUG   :     r8 00000002  r9 8e105ad0  sl 8e105ad0  fp 8ff31640
01-13 15:12:07.119 23330 23330 F DEBUG   :     ip 00000058  sp 8e0feee8  lr b0d0b517  pc b0d0dd80  cpsr 600b0010
01-13 15:12:07.129 23330 23330 F DEBUG   : 
01-13 15:12:07.129 23330 23330 F DEBUG   : backtrace:
01-13 15:12:07.129 23330 23330 F DEBUG   :     #00 pc 00049d80  /system/lib/libc.so (tgkill+12)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #01 pc 00047513  /system/lib/libc.so (pthread_kill+34)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #02 pc 0001d615  /system/lib/libc.so (raise+10)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #03 pc 00019161  /system/lib/libc.so (__libc_android_abort+34)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #04 pc 00017028  /system/lib/libc.so (abort+4)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #05 pc 000e12f7  /data/app/ca.fuwafuwa.kaku-1/lib/arm/libtess.so (_ZNK7ERRCODE5errorEPKc16TessErrorLogCodeS1_z+170)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #06 pc 000a4e25  /data/app/ca.fuwafuwa.kaku-1/lib/arm/libtess.so (_ZN9tesseract14ChoiceIteratorC1ERKNS_17LTRResultIteratorE+44)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #07 pc 0017c1e5  /data/app/ca.fuwafuwa.kaku-1/lib/arm/libtess.so (Java_com_googlecode_tesseract_android_ResultIterator_nativeGetChoices+32)
01-13 15:12:07.129 23330 23330 F DEBUG   :     #08 pc 000097ff  /data/data/ca.fuwafuwa.kaku/cache/slice-com.rmtheis-tess-two-6.1.1_ff6eb97b1edc3dca0f1bfaf9c3c054e06e8b0054-classes.dex (offset 0x10000)
01-13 15:12:08.079   829   850 I BootReceiver: Copying /data/tombstones/tombstone_05 to DropBox (SYSTEM_TOMBSTONE)
01-13 15:12:08.082   256   256 W         : debuggerd: resuming target 23231
01-13 15:12:08.132   829 10241 I VirtualDisplayAdapter: Virtual display device released because application token died: ca.fuwafuwa.kaku
01-13 15:12:08.132   829 10242 D GraphicsStats: Buffer count: 8
01-13 15:12:08.132   283   283 I Adreno  : DequeueBuffer: dequeueBuffer failed
01-13 15:12:08.133   829   853 I DisplayManagerService: Display device removed: DisplayDeviceInfo{"ca.fuwafuwa.kaku.MainService": uniqueId="virtual:ca.fuwafuwa.kaku,10149,ca.fuwafuwa.kaku.MainService,0", 2560 x 1440, modeId 30, defaultModeId 30, supportedModes [{id=30, width=2560, height=1440, fps=60.0}], colorTransformId 0, defaultColorTransformId 0, supportedColorTransforms [], HdrCapabilities null, density 560, 560.0 x 560.0 dpi, appVsyncOff 0, presDeadline 16666666, touch NONE, rotation 0, type VIRTUAL, state ON, owner ca.fuwafuwa.kaku (uid 10149), FLAG_PRESENTATION}
01-13 15:12:08.133   283   283 E DisplayDevice: eglSwapBuffers(0x1, 0xa74b6b60) failed with 0x0000300d
01-13 15:12:08.133   283   283 I Adreno  : flush reason set to EsxFlushModeReasonInvalidBinLayout
01-13 15:12:08.133   283   283 I Adreno  : flush reason set to EsxFlushModeReasonInvalidBinLayout
01-13 15:12:08.135   829  6652 I ActivityManager: Process ca.fuwafuwa.kaku (pid 23231) has died
01-13 15:12:08.135   829  6652 D ActivityManager: cleanUpApplicationRecord -- 23231
01-13 15:12:08.135   829  6652 W ActivityManager: Scheduling restart of crashed service ca.fuwafuwa.kaku/.MainService in 1000ms
01-13 15:12:08.138   829   853 W DisplayManagerService: Failed to notify process 23231 that displays changed, assuming it died.
01-13 15:12:08.138   829   853 W DisplayManagerService: android.os.DeadObjectException
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.os.BinderProxy.transactNative(Native Method)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.os.BinderProxy.transact(Binder.java:615)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.hardware.display.IDisplayManagerCallback$Stub$Proxy.onDisplayEvent(IDisplayManagerCallback.java:81)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at com.android.server.display.DisplayManagerService$CallbackRecord.notifyDisplayEventAsync(DisplayManagerService.java:1166)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at com.android.server.display.DisplayManagerService.deliverDisplayEvent(DisplayManagerService.java:1004)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at com.android.server.display.DisplayManagerService.-wrap6(DisplayManagerService.java)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at com.android.server.display.DisplayManagerService$DisplayManagerHandler.handleMessage(DisplayManagerService.java:1099)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.os.Handler.dispatchMessage(Handler.java:102)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.os.Looper.loop(Looper.java:154)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at android.os.HandlerThread.run(HandlerThread.java:61)
01-13 15:12:08.138   829   853 W DisplayManagerService:     at com.android.server.ServiceThread.run(ServiceThread.java:46)
01-13 15:12:08.138   283   283 W libEGL  : EGLNativeWindowType 0xa7383008 disconnect failed
01-13 15:12:08.147   829  1303 W InputDispatcher: channel 'f787c61 ca.fuwafuwa.kaku (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
01-13 15:12:08.147   829  1303 E InputDispatcher: channel 'f787c61 ca.fuwafuwa.kaku (server)' ~ Channel is unrecoverably broken and will be disposed!
01-13 15:12:08.147   829  1303 W InputDispatcher: channel 'e7b7447 ca.fuwafuwa.kaku (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
01-13 15:12:08.147   829  1303 E InputDispatcher: channel 'e7b7447 ca.fuwafuwa.kaku (server)' ~ Channel is unrecoverably broken and will be disposed!
01-13 15:12:08.148   298   298 I Zygote  : Process 23231 exited due to signal (6)
01-13 15:12:08.163   829 10239 I WindowManager: WIN DEATH: Window{f787c61 u0 ca.fuwafuwa.kaku}
01-13 15:12:08.163   829 10239 W InputDispatcher: Attempted to unregister already unregistered input channel 'f787c61 ca.fuwafuwa.kaku (server)'
01-13 15:12:08.163   829  9340 I OpenGLRenderer: Initialized EGL, version 1.4
01-13 15:12:08.163   829  9340 D OpenGLRenderer: Swap behavior 1
01-13 15:12:08.163   829 10239 I WindowManager: Destroying surface Surface(name=) called by com.android.server.wm.WindowStateAnimator.destroySurface:2014 com.android.server.wm.WindowStateAnimator.destroySurfaceLocked:881 com.android.server.wm.WindowState.removeLocked:1449 com.android.server.wm.WindowManagerService.removeWindowInnerLocked:2478 com.android.server.wm.WindowManagerService.removeWindowLocked:2436 com.android.server.wm.WindowState$DeathRecipient.binderDied:1780 android.os.BinderProxy.sendDeathNotice:688 <bottom of call stack> 
01-13 15:12:08.168   829 10244 I WindowManager: WIN DEATH: Window{e7b7447 u0 ca.fuwafuwa.kaku}
01-13 15:12:08.168   829 10244 W InputDispatcher: Attempted to unregister already unregistered input channel 'e7b7447 ca.fuwafuwa.kaku (server)'
01-13 15:12:08.249 23261 23281 E epsxe   :  * Frame per second (33) - Time 60 frames -> 1.778 seconds.
01-13 15:12:08.369  1849 20556 W ContentTaskController: Invalid newTask was provided to startTracking.
01-13 15:12:08.616   829   853 I WindowManager: Destroying surface Surface(name=) called by com.android.server.wm.WindowStateAnimator.destroySurface:2014 com.android.server.wm.WindowStateAnimator.destroySurfaceLocked:881 com.android.server.wm.WindowState.destroyOrSaveSurface:2073 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementInner:429 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:232 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:180 com.android.server.wm.WindowManagerService$H.handleMessage:8079 android.os.Handler.dispatchMessage:102 
01-13 15:12:08.755 23261 23281 E epsxe   :  * Frame per second (118) - Time 60 frames -> 0.506 seconds.

Screenshot: screenshot_20170113-152156

Shimizoki commented 7 years ago

The crash is repeatable. Interestingly, It only surfaces when you are doing a capture of that specific area in ePSXe, but not if you are capturing a screenshot of the same image.

Edit - Crash happens on the following line of Ocr/ResultIterator.java/getChoicesAndConfidence(int): String[] nativeChoices = nativeGetChoices(mNativeResultIterator, level); mNativeResultIterator = 2222941984; level = 4;

I cannot find any documentation on that function, nor do I see where it is defined locally. As such my debugging for the most part has stopped here.

Note - The sound glitches for a second when the app crashes, could be related, could just be the phone getting screwy during a crash.

Shimizoki commented 7 years ago

Crash seems to be caused due to the input screenshot containing the blue border of the captured area. OCR then is trying to figure out what is going on if the character is too near that edge. It would then treat the edge, and as such, the whole image as part of the kanji. The fix is simply to ensure the blue border is not part of the captured screenshot. (An offset of the border width is sufficient in testing)

0xbad1d3a5 commented 7 years ago

Thanks for the investigation. I agree with cropping out the blue border and intended to do that later, but it looks like the actual cause of the bug is something else.

I cut out the exact box from your screenshot and ran a unit test on it:

ocrfail

    @SmallTest
    public void testImage(){

        // Attempt to initialize the API.
        final TessBaseAPI baseApi = new TessBaseAPI();
        boolean success = baseApi.init(TESSBASE_PATH, "jpn");
        assertTrue(success);

        Bitmap bitmap = BitmapFactory.decodeFile(TESSBASE_PATH + "ocrfail.png");

        baseApi.setImage(bitmap);
        String hocr = baseApi.getHOCRText(0);
        String text = baseApi.getUTF8Text();
        ResultIterator resultIterator = baseApi.getResultIterator();

        resultIterator.begin();

        do {
            List<Pair<String, Double>> choicesAndConfidence = resultIterator.getChoicesAndConfidence(PageIteratorLevel.RIL_SYMBOL);
        } while (resultIterator.next(PageIteratorLevel.RIL_SYMBOL));
    }

It looks like the problem stems from the fact that tesseract actually didn't detect any words in that capture, so my call to resultIterator.getChoicesAndConfidence(PageIteratorLevel.RIL_SYMBOL) was invalid and threw an exception in Itrresultiterator.cpp at line 341: ASSERT_HOST(result_it.it_->word() != NULL).

I assumed the .next() function was to determine if the next word existed, but looks like it actually tests for end of file. So the proper fix would simply change the do-while loop into a while loop in OcrRunnable, and we shouldn't hit this bug again in the future if the OCR result ever comes back with no results.

0xbad1d3a5 commented 7 years ago

Actually wait. It looks like .next() goes to the next word and tests for EOF. Well, that kinda makes things a little more difficult...

Shimizoki commented 7 years ago

Try fixing the border, I pulled your baseline and changed it myself and the crashes stopped.

I changed OCRRunnable.java - Line: 180 to: Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, box.x+10, box.y+10, box.width-20, box.height-20);

It also seemed to greatly improve the accuracy of certain kanji.

You are right that the ACTUAL crash is due to it not finding any kanji. This can be repeated by uploading a perfectly black or white image. But the reason in this case it was not finding any was because the border is being treated as kanji as well.

0xbad1d3a5 commented 7 years ago

Right, I'm aware that fixing the border would probably fix this instance of the OCR, but the root cause was that the OCR Engine (tesseract) was not able to detect any characters in the box (for whatever reason). We can still hit this bug in the future despite cropping the border out if in the future tesseract again wasn't able to find any words.

I think I just fixed it, can you try commit 221a05b3349530d213760a8b15952f10aba95ef2 and see if the issue still exists?

0xbad1d3a5 commented 7 years ago

You are right that the ACTUAL crash is due to it not finding any kanji. This can be repeated by uploading a perfectly black or white image. But the reason in this case it was not finding any was because the border is being treated as kanji as well.

Ah. I see. Yes correct, that should be fixed as well. I was treating them as two separate issues. One being tesseract crashing on no words detected and the other to crop the image.

Would you like to submit a pull request for cropping the box (Issue #5)? One thing though, the border width is defined by drawable/border-transparent.xml and is set to 1dp. You shouldn't be using absolute pixel values (+10, +20, etc) in the createBitmap() function. There's a helper class called KakuTools that will convert dp to px for you, so please use that.

If you don't want to submit a pull request, that's fine too. I'll fix it later :)

Shimizoki commented 7 years ago

I have no problems offering assistance here and there, but I generally don't like pull requests unless the owner gives the ok before hand. Some people would prefer that it stays their own code. As such, I did not do anything this time via Git... so I can't actually do the request anyways.

As for the hardcoding... I just wanted some values in there to prove that it worked, doing it correct falls under what I said above. (Why do it right if you aren't going to use it)

I can verify that the change you made prevents the crash. However if no kanji is detected... perhaps a toast saying that would be nice. (It is a bit unnerving not being sure if it is calculating or already failed)

When you address #5, it will allow kanji to be detected in the image I provided, but it will pick up background noise as various things. If you wish, I have some temp code that will do some pre-processing of the image to clean it up quite a bit... but ideally I think you would want to use something other than the horrible algorithms I pieced together.

So... if you want me to do formal pull requests I can do that... your call.

0xbad1d3a5 commented 7 years ago

I'd love more help on the project, so if you're available and can help fix bugs, then by all means. Just make sure there's a issue made for each separate issue so discussions can happen beforehand before any code changes.

Do note that the project license is BSD-3 and all contributed code would fall under this license.

0xbad1d3a5 commented 7 years ago

This specific issue (Kaku crashes when there are no OCR'd characters) is fixed in 221a05b3349530d213760a8b15952f10aba95ef2. The other issues discussed here are being tracked in #5.