rxing-core / rxing

cRustacean Crossing
https://crates.io/crates/rxing
Apache License 2.0
198 stars 19 forks source link

Using webcam images in buffer #44

Closed menteb closed 8 months ago

menteb commented 8 months ago

Hi,

I'm trying to get to scan a barcode from live images. Using image and rscam works fine to get the image into memory. The following is my code to get the image from the live camera feed:

let img = match image::load_from_memory(&frame) {
        Ok(i) => i.to_rgba8(), // Convert to RGBA as required by rxing
        Err(e) => {
                eprintln!("Error processing image: {:?}", e);
                continue;
            }
};

I can't figure out how to get these types of images decoded to achieve the same as with an image on disk as per the example:

let results = rxing::helpers::detect_multiple_in_file(file_name).expect("decodes");
    for result in results {
        println!("{} -> {}", result.getBarcodeFormat(), result.getText())
    }

I am very new to Rust (and coding in general) and learning while I fail. Any help is welcome :)

hschimke commented 8 months ago

I think you have two options:

  1. The detect_multiple_in_luma function. In order to use that you will need to convert the RGB data to luminosity. An example of how this is done from an array of RGB data is available in the rxing-wasm crate, but keep in mind that this example is specifically designed to work with JavaScript RGBA values, and may not apply to what you are using. This might not be exactly what you want, though, since you already seem to be using the Image create to pull the image out of the memory buffer. That leads us to the second option.
  2. Skip using the helper functions and create your barcode decoder yourself. The helper functions are just a wrapper around the library’s core structs and traits. You can look at the code for the helper functions to see how they are doing it.

    
    
    let img = image::open(file_name)
        .map_err(|e| Exceptions::runtime_with(format!("couldn't read {file_name}: {e}")))?;
    let multi_format_reader = MultiUseMultiFormatReader::default();
    let mut scanner = GenericMultipleBarcodeReader::new(multi_format_reader);
    
    hints
        .entry(DecodeHintType::TRY_HARDER)
        .or_insert(DecodeHintValue::TryHarder(true));
    
    scanner.decode_multiple_with_hints(
        &mut BinaryBitmap::new(HybridBinarizer::new(BufferedImageLuminanceSource::new(img))),
        hints,
    )

So in this case you can see that you have an image already, so you should be able to skip the helper functions and access the library directly. This would be my preferred solution in your case, as it gives you more options on how you work with the library.
Another point, above you can see that we create a `MultiUseMultiFormatReader` which is the type of reader used when you intend to use the reader over and over again, so you would create that reader outside of your frame handling loop, and then call the `decode_multiple_with_hints` function of it inside the loop to decode the barcodes. Also note that the you had picked the “detect multiple” option, which is why I used the code for that, if you only think there is one barcode per image then you would use slightly different (and faster) code.

Feel free to reach out again if you have more questions.
hschimke commented 8 months ago

Closing for now, please re-open if you need additional help.