zxingify / zxingify-objc

An Objective-C Port of ZXing
Apache License 2.0
3.07k stars 753 forks source link

Hard to detect customized qr code #430

Closed neacao closed 6 years ago

neacao commented 6 years ago

Seems like with customized QR code. it's hard (can't) detect the information. qrcode-logo-design-starbucks

benjohnde commented 6 years ago

Have you tried it with zxing/zxing? Just curious.

neacao commented 6 years ago

Yeah, it can be decode by zxing. Result Here

benjohnde commented 6 years ago

I will take a lot a your example.

neacao commented 6 years ago

:+1: lets me know if it's resolved, i will help to make more tests :D

benjohnde commented 6 years ago

Hmm I can decode it :)

benjohnde commented 6 years ago

How do you decode?

QRCode can be tricky with 1080p, you should utilise 720p.

And: do you use the current version 3.4.0 of ZXingObjC?

neacao commented 6 years ago

@benjohnde sorry for trouble, I got the problem, seems like crop image function doesn't work correctly in my case & return wrong frame. The decode function is working well :+1:

benjohnde commented 6 years ago

Perfect!

neacao commented 6 years ago

@benjohnde sorry for trouble, just figured out a problem with ZXCGImageLuminanceSource that make the grayscale calculate wrong Reproduce steps:

1. Enable binaryLayer in BarcodeScanner example
2. Try scanning the image below in normal light
3. The yellow usually convert to white instead of black

qr5

benjohnde commented 6 years ago

That's a difficult one. I believe the yellow is too bright. Could you double check of zxing/zxing is able to resolve this one. I would not really want to change much of the Binarizer logic. We can do little adjustments, but most importantly: is the barcode designed against the official spec?

neacao commented 6 years ago

No, it's not, actually the ZXingObjC can detect this one, but it takes a while before the yellow area can be converted to black.

benjohnde commented 6 years ago

I believe it depends on the angle of the camera, the environment, lighting, etc.

neacao commented 6 years ago

That's true, if I resize the image above smaller, the lib can decode it faster, so I would recommend about pyramid image processing, it means scale the image multiple size to detect the qr code

neacao commented 6 years ago

@benjohnde how do you think about scaling ?

Problem

  1. Hard to detect QR code with large yellow area
  2. Hard to detect small QR code

Solution

  1. Scale image to x0.5, x1.0, x2.0 to decode
  2. Those images will be processed in concurrency mode (another dispatch queue)

Pros

  1. Resolved those ad-hoc cases

Cons

  1. Cost of image scaling
benjohnde commented 6 years ago

I am not sure if the scaling resolves the problem you experience. I strongly believe that in your particular case, as you also stated, the Binarizer translates the yellow pixels into white ones. Maybe we could add a more loose Binarizer, when it comes to yellow pixels, to help you with those customized qr codes. We could add a toggle via ZXDecodeHints. Having said that, we would not alter code which is derived from zxing, but could add an alternative way for your cases in handling yellow pixels.

benjohnde commented 6 years ago

Even though scaling may lead to a different behaviour of binarizing, it strongly recommend that you would better stick to direct Binarizer adjustments.

neacao commented 6 years ago

Actually I have implemented those scaling images to see if the idea could work or not. Under x0.5, the yellow are could keep the black pixels & also image's feature, when x2.0 could decode the image w/out zooming. This is just an option can enable by user (or not). You'r right, we should keep everything same as ZXing, but if we add more loose Binarizer, could it effect to other results of normal cases ? If not, can you provide some key points, so I can support to make another PR for this thing 😁

neacao commented 6 years ago

@benjohnde I found this doc

http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6

Could we use Method 4 – Decomposition using minimum values to convert grayscale. The goal is not a smooth grayscale image but better black/white pixels, so each pixel should be: rgbPixelOut = MIN(red, MIN(blue, green));

So instead of scaling, could we force lib process for both of darker grayscale image & normal grayscale image πŸ€”

benjohnde commented 6 years ago

Nice find @neacao! Love the drive. If all tests are passing, you can reach in a pull request or I may help out.

We could add some sort of additional ZXDecodeHints to reflect both, the difference to zxing and to let the user decide whether he wants to use additional processing πŸ€”.

neacao commented 6 years ago

@benjohnde I have found a better way to process, we could use shades of gray image to apply for each frame (Method 6), that's better because the Min's formula might translate the background to black. I will prepare another PR for this, but should I add ZXDecodeHints onto ZXCGImageLuminanceSource to switch between original formula & customized oneπŸ€”

benjohnde commented 6 years ago

I believe the best way to toggle that feature is to use ZXDecodeHints but I am not quite sure about how to inject the hint in ZXCGImageLuminanceSource tbh. Will think about that πŸ€”

neacao commented 6 years ago

How about define an enum for grayscale method inside ZXDecodeHints Example:

typedef NS_ENUM(NSInteger, ZXLuminanceSourceType) {
 Normal,
 Luma, 
 Shades,
 ...
}

This enum should be located at ZXLuminanceSource.h

benjohnde commented 6 years ago

Good idea!

neacao commented 6 years ago

Instead of add to ZXLuminanceSource.h (from core), we can create new ZXCGImageLuminanceSourceInfo to handle this, so the core would not change but client

benjohnde commented 6 years ago

I like your implementation #446. Maybe one TestCase to roughly cover the branch of ZXCGImageLuminanceSourceShades and ZXCGImageLuminanceSourceDigital would be awesome. I am busy today, so I would merge this branch tomorrow after some testing session!

neacao commented 6 years ago

Sure, i will