Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WeChat QRCode module open source. #2821

Merged
merged 6 commits into from
Jan 21, 2021
Merged

Conversation

dddzg
Copy link
Contributor

@dddzg dddzg commented Jan 15, 2021

Merge with 3rdparty: opencv/opencv_3rdparty#59

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • The feature is well documented and sample code can be built with the project CMake

There is an open-source version of the WeChat QR code detector.

Check #2809 for more information.

force_builders=ARMv7,Custom
build_image:Custom=centos:7
buildworker:Custom=linux-1

build_image:Docs=docs-js
allow_multiple_commits=1

@dddzg dddzg mentioned this pull request Jan 15, 2021
4 tasks
@dddzg
Copy link
Contributor Author

dddzg commented Jan 16, 2021

Hi @alalek, sorry for bothering you again. Now, the code successfully supports different platforms. However, there are two issues that we meet:

  1. As we can see, the patch size exceeds 1MB, could we ignore this warning?
  2. during debugging on iOS, we find that we can't name the API class as QRCodeDetector because there is a QRCodeDetector in OpenCV objdetect module. Even though they are under different modules (one is under objdetect and the other is under wechat_qrcode, check logs below), there is still an error. Maybe it is a feature, not a bug for iOS. So we rename the QRCodeDetector class as WeChatQRCode temporarily. What are your ideas?

logs:
error: Multiple commands produce '/Volumes/build-storage/build/precommit-contrib_ios/build/build_ios_contrib/build/build-armv7-iphoneos/lib/Release/opencv2.framework/Headers/QRCodeDetector.h':

  1. Target 'opencv2' (project 'opencv2') has copy command from '/Volumes/build-storage/build/precommit-contrib_ios/build/build_ios_contrib/build/build-armv7-iphoneos/modules/objc_bindings_generator/ios/gen/objc/objdetect/QRCodeDetector.h' to '/Volumes/build-storage/build/precommit-contrib_ios/build/build_ios_contrib/build/build-armv7-iphoneos/lib/Release/opencv2.framework/Headers/QRCodeDetector.h' `
  2. Target 'opencv2' (project 'opencv2') has copy command from '/Volumes/build-storage/build/precommit-contrib_ios/build/build_ios_contrib/build/build-armv7-iphoneos/modules/objc_bindings_generator/ios/gen/objc/wechat_qrcode/QRCodeDetector.h' to '/Volumes/build-storage/build/precommit-contrib_ios/build/build_ios_contrib/build/build-armv7-iphoneos/lib/Release/opencv2.framework/Headers/QRCodeDetector.h'

@alalek
Copy link
Member

alalek commented Jan 16, 2021

This repository should store source code only. Models and other data blobs should be stored externally.
(There is an exception for images for samples / documentation only. Images for tests are stored in opencv_extra).

There are several options:

  • opencv_3rdparty repository with data on branches (example for face detector DNN data). Usually used with C++ code (downloaded by CMake scripts). This data is downloaded through https://raw.githubusercontent.com (AFAIK, this may cause issues for devs from China due to GFW)
  • GoogleDrive, DropBox, etc (need to check if CMake is able to download data from these locations (to use in C++ code) - there are several limitations). There are no OpenCV accounts for that. Authors use their own.

Take a look ocv_download() function in CMake scripts.


There is CV_WRAP_AS(WeChatQRCode) / CV_EXPORTS_AS(WeChatQRCode) macros. Need to check if Obj-C binding generator support that.

Headers/QRCodeDetector.h

In general binding generator should handle nested namespaces (target name may look like <namespace>_<className>). Perhaps we need to improve generator first. Consider disabling objc wrapper for now.

Just renaming to WeChatQRCode should be OK too.

@dddzg
Copy link
Contributor Author

dddzg commented Jan 18, 2021

Hi, @alalek . I have added ocv_download related code. There is a new pull request for opencv_3rdparty opencv/opencv_3rdparty#59. Please check it out. I can't start a pull request to the wechat_qrcode branch, so I start a pull request to the readme branch for opencv_3rdparty. Could you help me?

BTW, there are still some issues:

  1. I have moved the models with ocv_download. However, the code is too much. It still exceeds the 1MB patch limit. Could we ignore it?
  2. For ocv_download, I didn't find a standard requirement about DESTINATION_DIR. Now, it is set to "${CMAKE_BINARY_DIR}/downloads/wechat_qrcode". What are your ideas?
  3. As you mentioned <namespace>_<className>, it reminds me that, for the python binding generator, it also follows <namespace>_<className> template. So, it leads to a little weird API result likes cv2.wechat_qrcode_WeChatQRCode (can we adjust it to cv2.wechat_qrcode.WeChatQRCode or cv2.WeChatQRCode). For C++, it looks well for cv::wechat_qrcode::WeChatQRCode

@alalek
Copy link
Member

alalek commented Jan 18, 2021

Thank you for update!

I can't start a pull request to the wechat_qrcode branch

Please prepare 2 commits in this PR:

  • base branch is root (currently it is readme which is not correct), you can change target branch in proposed PR using the "Edit" button.
  • 1st commit with readme file (I will create wechat_qrcode branch on this commit before the merge)
  • 2nd commit with models itself (I will create wechat_qrcode_20210115 branch during the merge)

(no need to re-create PR, use --force push option)


However, the code is too much. It still exceeds the 1MB patch limit.
dddzg wants to merge 59 commits

Need to squash commits into one (all binaries are still in git history)


I didn't find a standard requirement about DESTINATION_DIR.
Now, it is set to "${CMAKE_BINARY_DIR}/downloads/wechat_qrcode". What are your ideas?

This is the right path.


it leads to a little weird API result likes cv2.wechat_qrcode_WeChatQRCode

Agreed, we need to take a look on this.

cv2.wechat_qrcode.WeChatQRCode

Submodules are not supported yet in Python bindings. However it makes sense (but we need to preserve existed Python API too to avoid breaking of Users code).

@vpisarev Any suggestions about bindings?

@vpisarev vpisarev self-requested a review January 19, 2021 10:45
@vpisarev vpisarev self-assigned this Jan 19, 2021
@vpisarev
Copy link
Contributor

vpisarev commented Jan 19, 2021

@dddzg, @alalek, in my opinion, the patch looks great. I suggest to merge it in and adjust Python bindings/fix ObjC bindings etc. later if needed. It's usable, it works really well and that's enough for now.

@dddzg, may I ask you to do 2 more things:

  1. take the updated C++ example from here: https://github.com/vpisarev/opencv_contrib/blob/wechat_qrcode/modules/wechat_qrcode/samples/qrcode_example.cpp. It would be nice if the Python example is updated in a similar way.

  2. make sure all the builders are green (except for the doc builder which will report warning about the patch size). Then squash commits into one:

$ git reset --soft HEAD~number_of_commits_in_PR  # now it would be 59, but after updating qrcode_example.cpp (and optionally qrcode.py the number will increase)
$ git commit
$ git push --force origin

after it the pull request will contain just 1 commit and the doc builder warning will gone, since the patch will not include model files anymore.

@dddzg
Copy link
Contributor Author

dddzg commented Jan 19, 2021

Sorry for the delay.
Hi @alalek, I have updated the opencv_3rdparty with 2 commits, opencv/opencv_3rdparty#59.
Hi @vpisarev , thanks for your suggestions, I have updated the C++ and python examples and squashed commits into one.

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the opencv_3rdparty with 2 commits

Update looks good. Thank you!

modules/wechat_qrcode/CMakeLists.txt Outdated Show resolved Hide resolved
@vpisarev
Copy link
Contributor

@alalek, all the tests pass now; in my opinion, PR is ready to be merged 👍

@vpisarev
Copy link
Contributor

@alalek, if you do not have any objections, I suggest @dddzg to squash commits into one once again; then it can be merged using our automated tool

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great contribution!

modules/wechat_qrcode/LICENSE Outdated Show resolved Hide resolved
modules/wechat_qrcode/src/binarizermgr.cpp Outdated Show resolved Hide resolved
modules/wechat_qrcode/src/detector/align.hpp Outdated Show resolved Hide resolved
modules/wechat_qrcode/samples/qrcode.py Outdated Show resolved Hide resolved
* maxepoches max iteration epochs
* minchanged min central change times
*/
vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches, uint minchanged) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future TODO: try to reuse cv::kmeans()

* Ends up being a bit faster than {@link Math#round(float)}. This merely
* rounds its argument to the nearest int, where x.5 rounds up to x+1.
*/
static inline int round(double value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future TODO: cvRound()

modules/wechat_qrcode/src/wechat_qrcode.cpp Outdated Show resolved Hide resolved
modules/wechat_qrcode/src/wechat_qrcode.cpp Outdated Show resolved Hide resolved
modules/wechat_qrcode/src/wechat_qrcode.cpp Outdated Show resolved Hide resolved
modules/wechat_qrcode/src/wechat_qrcode.cpp Outdated Show resolved Hide resolved
Comment on lines +103 to +104
auto res_points = vector<Mat>();
auto ret = p->decode(input_img, candidate_points, res_points);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are points fixed size? 4 points per instance?

if so, then it make sense to return 2D Mat instead of vector:

  • rows are instances
  • cols(=4) are corners points of CV_32FC2 elements (C2 means 2 channels for x/y components)

Copy link
Contributor Author

@dddzg dddzg Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, 4 points per instance, but the row size of points is not fixed. Because our detector supports detecting multiple QRcode in an image. Moreover, not all detected QRCode can be decoded. So, there are candidate_points detected by the detector. Then we try to decode them one by one. For the successfully decoded qrcode, we will append their points to the res_points.

So, I prefer to use the vector, which is more convenient to append. Could we keep it?
I am not very familiar with OpenCV 2D Mat, is it convenient to append new rows?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiple QRcode in an image

So, what is represented by each vector element? 4 points corners?


This question is about external API representation (points output argument). Internal implementation can be any (we don't worry about that).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalek, I suggest to merge the current PR as-is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpisarev Please make careful reviews. For example, .fixedType() check below doesn't make any sense. Are you going to fix that?

Copy link
Contributor Author

@dddzg dddzg Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalek Yes, each Mat in vector represents 4 points corners, it can also be represented as Mat(4, 2, CV_32FC1). And the format is the same with OpenCV QRcodeDetector

Copy link
Contributor Author

@dddzg dddzg Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @alalek , the code fixedType() comes from https://github.com/opencv/opencv/blob/7a790d0d353bcbe48f1d62fb917c787ab4185846/modules/objdetect/src/qrcode.cpp#L49 (the opencv qrcode module) Because I try to convert vector<Mat> to OutputArrayOfArrays. Do you have any good ideas?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dddzg
Hello, are there any steps for use and deployment? I want to try to use it in Golang, but I can't run the project of wechat_qrcode. Cmake is always running unsuccessfully, and I meet all kinds of errors, which makes me very upset!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you list the errors with more details?

@opencv-pushbot opencv-pushbot merged commit 905994d into opencv:master Jan 21, 2021
@alalek
Copy link
Member

alalek commented Jan 21, 2021

@vpisarev Do you want to merge opencv_3rdparty?

Why do you violate existed rules? ("fixup" commits should not go to upstream repository)

Comment on lines +100 to +109
// opencv type convert
vector<Mat> tmp_points;
if (points.needed()) {
for (size_t i = 0; i < res_points.size(); i++) {
Mat tmp_point;
tmp_points.push_back(tmp_point);
res_points[i].convertTo(((OutputArray)tmp_points[i]),
((OutputArray)tmp_points[i]).fixedType()
? ((OutputArray)tmp_points[i]).type()
: CV_32FC2);
Copy link
Member

@alalek alalek Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.fixedType() is used with external arguments only (mentioned file from objdetect follows this rule).
No sense to use it with "local" variables.


good ideas

Reuse conventions from external API of objdetect/QRCodeDetector
This code is expected here.


Update: file from objdetect is valid partially

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I will remove it.

Copy link
Contributor Author

@dddzg dddzg Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalek Could we reopen this PR or open a new PR?

@vpisarev
Copy link
Contributor

@alalek, it looks like our tool does not merge opencv_3rdparty, and I do not have permissions to merge into it manually. So, could you please do it?

@dddzg, open the new PR, this one is merged already

@dddzg dddzg mentioned this pull request Feb 1, 2021
6 tasks
@alalek alalek mentioned this pull request Apr 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants