Wechat QR Reader in Rust using Opencv
Published: 2023-08-31 10:04:40

## Introduction

WeChat Computer Vision Team has a QR detection and super resolution caffe model that outperforms the QR detection and decoding methods in the OpenCV objdetect library. You need to compile the opencv contrib packages from source if you want to take advantage of this high performance QR library.

Take a look at my github repo.

[rust-wechat-qr-reader](https://github.com/rajeshpachaikani/rust-wechat-qr-reader)

## Prepare resources

We need to compile opencv and opencv_contrib packages. You can fetch them using the following commands

```
mkdir ~/opencv_build && cd ~/opencv_build
mkdir build
git clone git@github.com:opencv/opencv.git - depth 1
git clone git@github.com:opencv/opencv_contrib.git - depth 1
```


There are several dependencies to be installed based on your OS.

In windows, you can install the msvc or mingw compiler and follow the instruction in the opencv and keep your fingers crossed since the last time I tested in windows the rust opencv bindings were not able to generate due to some bug in the visual studio build tools.

In Linux, you can use clang or GCC compiler. I prefer and tested with clang compiler only.

In both platforms we can use cmake-gui to configure the OpenCV project.

You can use apt, pacman or yum based on the distro you are using to install all the dependencies.

## Configure

Open CMake-Gui and select the source code folder `~/opencv_build/opencv`

![Source and Build directory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjcwd4mjrcsi2ojurao3.png)

Select `~/opencv_build/build` as build directory and click Configure


![CMake setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi07sg2xbvk6ihosttiv.png)

Keep “Unix Makefiles” as the generator and click on Specify native compilers. Use the compiler of your choice here.

![Select Compiler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ix7awz4ip37ji864ch37.png)
Internet is required while running Configure, as cmake will attempt to download some zip files.

Once Configure is finished you will see several build options.

![Cmake Configure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipeg9n8bux96hoiwpoqo.png)
Search for `OPENCV_EXTRA_MODULES_PATH` and add `~/opencv_build/opencv_contrib/modules` as module path

![Add contrib modules path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2yd42wrpj0x2hpjbqv1.png)
Now click on Configure again. This will read the modules path and add more build options. Search for BUILD_opencv_wechat_qrcode and make sure it is enabled.

![Add contrib modules path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwqwgmsqwfj79azl5o5d.png)
Now click on Generate. This will create Unix Makefiles in the build directory.

Now open your terminal and navigate to the build directory. The make command will start building the opencv library. The `-j8` flag specifies the number of jobs (commands) to run simultaneously. If you have more than 8 cpu cores you can use a larger number so that the compilation will finish faster.

```
cd ~/opencv_build/build
make -j8
```

![make command output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vnnns65g7lcz6rxc93ok.png)
Once the build is finished run sudo make install to install the library files in appropriate locations.

In order to make the library accessible from rust binary, we need to add the opencv lib directory to the /etc/ld.so.conf.d/libopencv.conf file

```
sudo nano /etc/ld.so.conf.d/libopencv.conf
```
and add this line `/usr/local/lib`

Save and exit from nano. Execute sudo ldconfig to load the libraries into environment.
Rust project

Finally, we can start working on the rust code. Create a new rust project by running cargo new --bin qr-app

Add opencv as a dependency by running cargo add opencv

Download the wechat qr code caffe models from their github repo . The following code need the caffemodel and prototxt files to be in the model directory.


![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qm2syy3sk97q3t8vs1oo.png)
```

use opencv::prelude::*;
use opencv::{highgui, videoio, wechat_qrcode::WeChatQRCode};

fn main() {
    let mut scanner = WeChatQRCode::new(
        "./model/detect.prototxt",
        "./model/detect.caffemodel",
        "./model/sr.prototxt",
        "./model/sr.caffemodel",
    )
    .unwrap();

    let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY).unwrap();
    let mut points = opencv::core::Vector::<opencv::core::Mat>::new();
    let mut frame = Mat::default();

    loop{
        cam.read(&mut frame).unwrap();
        let decoded = scanner.detect_and_decode(&frame, &mut points).unwrap();
        if points.len() >0{
            println!("{:?}", decoded);
        }

        highgui::imshow("winname", &frame).unwrap();
        highgui::wait_key(1).unwrap();
    }
}
```

The code is less than 30 lines and is really simple. The detect_and_decode function returns the vector<String> which contains the decoded list of texts corresponding to the QR code. We grab the frames from the inbuilt webcam in this example, if you need to read files from the hard disk you can use opencv::imgcodecs::imread(filename, flags) and pass the image to the detect_and_decode function. `cargo run` will compile and run the QR scanner application.


That’s all. Thank you for reading till the end. Please leave your comments and let me know what you think about my blogs. Bye!