B4A Library OpenCV 3.x

OpenCV (Open Source Computer Vision Library) is a really huge project/framework actively developed, mainly written in C++ . It is released under a BSD license.
Read more here: http://opencv.org/
OpenCV versions: https://opencv.org/releases/


OpenCV library for B4A: wraps the official OpenCV 3.x release for Android (in fact not all, about 95% of it)
  • Feel free to test and use it. You can even
  • License: You can use it for your projects, but you are not allowed to distribute nor sell this library. Of course you can distribute apps that use it (remember that OpenCV itself has BSD license as stated before)
  • Supported hardware is: armeabi-v7a and arm64-v8
  • Versions
    • 1.04 (2020/05/17)
      • This version wraps OpenCV 3.4.1 Android release and fixes some bugs (mostly some instance methods and some not exposed classes) of the previous version.
      • One of the major additions is the DNNmodule and related classes.
      • Link to the B4A library files: HERE :)
    • 1.00 (2017/09/27)
      • First B4A library wrapper (OpenCv320forB4A V1.00) which replicates (95%) the official OpenCV 3.20 Java API for Android.
      • (removed link. Use 1.04)

  • Please note that my support will be limited to issues with the wrapper itself, not to help translating OpenCV code from other languages to B4A 🤷‍♂️


========================================================================

(There may be some inaccuracies in what I expose in this post, related to the OpenCV project, since I am relatively new to it and don't know all about its internals. If you find any, please let me know and I will correct it)

A bit of explanation
There exist 'official' OpenCV wrappers for different languages and platforms. Android is one of them.
The official OpenCV 3.20 for Android API includes a lot of classes, organized in modules. But it does not include "all" the original OpenCV modules (since there are other 'experimental', non-free, or platform specific modules which may be present in other platforms but not for Android). Also, there are build options to "tune" it...

I have played quite a lot with it this last year, with a huge project which I started with inline Java, and also translating examples or testing features. But what I have used is just a small percent of the classes and methods exposed. So, there may be some (let's hope not too many) things to fix.

How to learn OpenCVforB4A
If you have worked before with OpenCV, the learning curve will be easy.
If it was using Java with OpenCV for Android, then it will be immediate, since all the methods have exactly the same syntax (except for initializers, polimorphism, and some special cases where simply I did my best).
Anyhow, the ways that I can think of, are (will add links later, also suggestions as online tutorials,.. are welcome)
  • Attached examples.
  • B4A OpenCV Tutorials. I will write a couple of them with what I consider the most important building pieces (for instance the Mat class, which in B4A is OCVMat) and modules
  • Internet examples: there are A LOT of examples over there, written in C++, Java, Python, JavaCV. I would look for examples in the language that is easier to understand for you and then try to translate. Some tips about it (based on my experience)
  • OpenCV syntax has changed as new versions. So there is an 'old' syntax in which nearly everything started with "cv...". Since version 3.X, there was 'cleaner' organization (project was written in C++ instead of C), and there were major syntax changes.
  • JavaCV: Translating from JavaCV to OpenCV should be quite easy but not always direct. JavaCV uses a mix of the old OpenCV syntax with some of its own, and at the beginning it can be a bit confusing, but then it is also easy.
  • Python: there is a lot of material...

First steps. Prepare for some crashes...
  • In OpenCV nearly everything takes part in the native code.
  • When we call a Sub/method/algorithm, it performs some internal checks to see if all the input data is correct. This check is perfomed in the native side. If something is not correct (wrong OCVMat dimensions, some incoherent parameters,...) it throws an exception and crashes. If we are lucky, perhaps we see in the log some clues about the check that made it crash.
  • On the good side, it is very easy to achieve results with OpenCV (check the examples). The real difficult part, as with many other things, is to fine-tune it: OpenCV has a collection of really powerful 'primitive' objects and operations, and really complex algorithms that can do many things. But it is the user who has to glue all of them to achieve the desired results.


(from the previous Beta announcement)
  • IMPORTANT: you must take this into account:
  • OpenCV (the included binary modules) is a free(*) project, but subject to license terms as described here: http://opencv.org/
    • (*): There are some modules in the OpenCV project which are on-free, but here I am refering to the ones included in the library
  • My work: (the B4A library) is free to test and use, but you can for it :). I'll keep donators updated with "advanced" material and examples
  • If you are interested, please PM me with your mail address and I will send you a link with the library and some basic examples. (be patient if you don't receive it immediately, I'll do it as soon as possible).
  • There is no documentation. In short, the syntax is nearly-exactly the same as the OpenCV3.20 Java API, adding "OCV" prefix and only the minimum modifications to adapt to B4A, For reference (taking into account described syntax changes) you can look at http://docs.opencv.org/java/3.1.0/ (which is not the latest one, but the API is nearly the same).
  • It would be preferable if you have worked before with OpenCV and/or can translate examples from Java/C++ and/or simply are interested in it.
  • I recommend starting with the examples and try to understand what is done. Just experimenting can lead to crash after crash of the native libraries with nearly no useful information, and can be very discouraging.
  • I forgot, the included binaries are for ameabi-v7a and arm64-v8 devices
---------------------------------------------------------------------
Some screenshots taken from the examples
Canny operator - Features2D - Color space conversion
s1.png
2D-FFT
s2.png
Color Blob detection
s3.png
 

Attachments

  • JavaCameraView2.zip
    2.7 KB · Views: 1,696
  • CameraOpenCvTest7.zip
    8.9 KB · Views: 1,182
  • BlobDetector5.zip
    15.3 KB · Views: 1,107
  • FaceDetector8.zip
    21 KB · Views: 1,168
Last edited:

JordiCP

Expert
Licensed User
Longtime User
According to the code I see, it happens because you are processing a copy of the preview Mat but not drawing this processed copy it anywhere (it only happens automatically when you use JavaCameraView) --> check the example that was made with cameraEx Class and you'll notice that, once processed, the resulting Mat was converted to a bitmap which is drawn/attached to a view

--EDIT--

Also, these lines are wrong (assigning a bitmap to mbm and then initting it)
B4X:
mbm = cam.GetPreviewBitmap(480,640)
'    Log(cam.PreviewSize.Height& "  " & cam.PreviewSize.Width)
   mbm.InitializeMutable(480,640)
 
Last edited:

biometrics

Active Member
Licensed User
Longtime User
(edit, didn't see the reply until it was too late ;))

Hi roberto,

Out-of-the-box OpenCV for Android build only has support for MJPEG encoded videos in .AVI container (even if the API allows so many options ... I was also surprised at the beginning). HERE you can read a bit more about it.

So I would check first if your file is MJPEG encoded.
  • If the answer is positive (i.e., your video file is already MJPEG encoded), please test your video with the attached code. It is an example that I was just preparing. You will see that there are some things slightly different that in your code ( I think the initialize2() method that you are using is not correct in my library and have to fix or remove it)
  • If not, you should convert it either externally on your PC, or internally with some transcoder (I tested not much ago @moster67 ffmpeg and it worked perfect for me)
In the future I may add internal ffmpeg support (if I find time and get how to do it), or an internal H264 encoder/decoder if I find a nice example to integrate. But it is not in my priority list since there are workarounds, and is not a limitation of my wrapper but of the standard OpenCV for Android build.

B4X:
#Region  Project Attributes
   #ApplicationLabel: OCV VideoCapture
   #VersionCode: 1
   #VersionName:
   'SupportedOrientations possible values: unspecified, landscape or portrait.
   #SupportedOrientations: landscape
   #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
   #FullScreen: False
   #IncludeTitle: True
#End Region


Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
 
   Dim t As Timer
 
   Dim VIDEO_SRC As String = "myvideo9.avi"         'Has to be MJPEG encoded.
 
End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim ocl As OCVOpenCVLoader
 
   Dim mCore As OCVCore
   Dim mImgProc As OCVImgproc

   Dim MyMatBGR As OCVMat
 
   Dim mVideoCapture As OCVVideoCapture
 
   Dim myVideoCaptureMat As OCVMat
   Dim myVideoCaptureBitmap As Bitmap
 
   Dim capturing As Boolean=False
   Dim P As Panel
   Dim btnStartStop As Button
 
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:

   ' As it is a demo, set everything to 640X480, since we know the video has that size
   P.Initialize("")
   Dim HH As Int = 80%Y
   Dim WW As Int = HH*640/480       'Keep aspect ratio for this example.
   Activity.AddView(P,(100%X-WW)/2,(100%Y-HH)/2,WW,HH)     ' Center screen

   myVideoCaptureBitmap.InitializeMutable(640,480)
   P.SetBackgroundImage(myVideoCaptureBitmap)
 
   'Control Button
   btnStartStop.Initialize("btnStartStop")
   btnStartStop.Text="Start"
   Activity.AddView(btnStartStop,20dip,20dip,80dip,40dip)
 
   t.Initialize("t",500)
 
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   capturing=False
   mVideoCapture.release
   t.Enabled=False
   Activity.Finish
End Sub

Sub btnStartStop_Click
 
   If Not(capturing) Then
     InitVideoCapture
   Else
     mVideoCapture.release
     btnStartStop.text="Start"
     t.Enabled=False
     capturing=False
   End If

End Sub


Sub t_tick
   If Not(t.Enabled) Then Return     'just in case it was a pending event
   If Not(capturing) Then Return
   Log("Tick")
   If mVideoCapture.isOpened Then
     If (mVideoCapture.read(myVideoCaptureMat)) Then
    
       If Not(myVideoCaptureMat.empty) Then 'really needed? should test
    
         'From https://github.com/opencv/opencv/issues/4974
         '// get some meta data about frame.
         'double fps = capture.get(Videoio.CAP_PROP_FPS);
         'double frameCount = capture.get(Videoio.CAP_PROP_FRAME_COUNT);
         'double h = capture.get(Videoio.CAP_PROP_FRAME_HEIGHT);
         'double w = capture.get(Videoio.CAP_PROP_FRAME_WIDTH);
         'double posFrames = capture.get(Videoio.CAP_PROP_POS_FRAMES);
         'double posMsec = capture.get(Videoio.CAP_PROP_POS_MSEC);
         'double speed = capture.get(Videoio.CAP_PROP_SPEED);
    
         Log("mVideoCapture has read!" & myVideoCaptureMat.rows &" "&myVideoCaptureMat.cols)
         Dim mUtils As OCVUtils
         mUtils.matToBitmap(myVideoCaptureMat, myVideoCaptureBitmap,False)
         P.Invalidate
    
       End If
     End If
   Else
     Log("mVideoCapture is not open")
   End If
 
End Sub


Sub InitVideoCapture
 
   mVideoCapture.Initialize1(File.Combine(File.DirRootExternal,VIDEO_SRC),0)
   If mVideoCapture.isOpened Then
     Log("VideoCapture file correctly opened")
     t.Enabled=True
     capturing=True
     btnStartStop.Text = "Stop"
   Else
     ToastMessageShow("VideoCapture failed to open.",True)
     capturing=False
     btnStartStop.Enabled = False
   End If
 
End Sub
Hi @JordiCP,

I can't get this to work. I believe my .avi is correctly encoded but I'm getting False on .isOpened. Could you please make myvideo9.avi available so I can test with the same file you used.
 

JordiCP

Expert
Licensed User
Longtime User
If I remember correctly, it had to be first copied to the internal libraries folder and wait for a while since the copy operation is async.
Can you check it?

I'll be able to look for the video or any other that works tomorrow
 

biometrics

Active Member
Licensed User
Longtime User
If I remember correctly, it had to be first copied to the internal libraries folder and wait for a while since the copy operation is async.
Can you check it?

I'll be able to look for the video or any other that works tomorrow
I copied my videos to File.DirRootExternal manually. So it's been there for a while before I ran the code, so I don't think that's a problem. Would appreciate your working .avi. If that works then my colleague that's a video encoding expert can inspect it and get the exact profile we need.

Edit: Added a File.Exists check to make sure.
 

JordiCP

Expert
Licensed User
Longtime User
If it isn't due to file access permissions issues, then the only thing I can think of is indeed an issue with the file format or perhaps the file size (too big?)

As said, I'll be able to look at it tomorrow, but I'm not even sure that I have my original avi file, although it should work with others.
 

biometrics

Active Member
Licensed User
Longtime User
If it isn't due to file access permissions issues, then the only thing I can think of is indeed an issue with the file format or perhaps the file size (too big?)

As said, I'll be able to look at it tomorrow, but I'm not even sure that I have my original avi file, although it should work with others.
Thanks for the clue, a smaller file is working. Not sure if it's the file size, bit rate, aspect ratio or what. They are all different. The latest working file is 8MB, 720x576, 25 fps.
 

biometrics

Active Member
Licensed User
Longtime User
Managed to get it to work with any video by converting with ffmpeg:

B4X:
ffmpeg -i input.mp4 -vcodec mjpeg output.mjpeg
ffmpeg -i output.mjpeg -vcodec mjpeg output.avi

Though that produces low bit rate files at the original high resolution, so I used the -q:v parameter to keep the video quality high and the -s to reduce the size.

B4X:
ffmpeg -i input.mp4 -vcodec mjpeg -q:v 1 -s 640x360 output.mjpeg
ffmpeg -i output.mjpeg -vcodec mjpeg -q:v 1 -s 640x360 output.avi

I find the OpenCV decoding to be very slow. Not sure why...
 

JordiCP

Expert
Licensed User
Longtime User
I find the OpenCV decoding to be very slow. Not sure why...
Yes. I guess it's due to the fact that, since ffmpeg itself is not a part of Opencv, it is included in some builds as a pre-compiled 3rd party binary (with limited decoding options, possibly due to licenses not being the same, and not necessarily with the fastest build options ...in short, decoding itself is not the main scope of Opencv).

I think that a custom build of all the project with a full and optimized ffmpeg could perhaps improve it, but that's not a straightforward change
 

biometrics

Active Member
Licensed User
Longtime User
Yes. I guess it's due to the fact that, since ffmpeg itself is not a part of Opencv, it is included in some builds as a pre-compiled 3rd party binary (with limited decoding options, possibly due to licenses not being the same, and not necessarily with the fastest build options ...in short, decoding itself is not the main scope of Opencv).

I think that a custom build of all the project with a full and optimized ffmpeg could perhaps improve it, but that's not a straightforward change
We just really wanted to go record real world videos as tests and play them in the office. But we'll just use a Windows PC to play the videos and point the Android camera at it. Will also work, just not very elegant. So not a big deal.
 

lingqdy1

Member
Hi Jordi, I am refering to your Example ImageManipulation2 where the points of a circle are detected. This is the part of your code:
B4X:
        Dim circles As OCVMatOfPoint3f
        circles.Initialize  
'dp=1 --> 算法的比例因子。1=从原始图像开始
'minDistance --> 以防止误报。但是,如果圆是同心的,则将此系数保持尽可能小
'mImgProc.HoughCircles1( tmpMatGray,circles,mImgProc.HOUGH_GRADIENT,1,10)
mImgProc.HoughCircles(tmpMatGray,circles,mImgProc.HOUGH_GRADIENT,1.0d,10,150,100,20,240)
'函数 HoughCircles 返回一个 3 点 (x,y,radius) 的数组
日志(circles.rows&“ ”&circles.cols&“ ”&circles.depth)
将 allCircles() 调暗为 OCVPoint3= circles.toArray()
对于 k=0 到 allCircles.Length-1

Log(“检测到的圆: x=”&allCircles(k).x &“ y=”& allCircles(k).y &“ radius=”& allCircles(k).z)
[/代码]
我想检测[B]线而不是圆,[/B]但我无法弄清楚线的必要声明。没有 OCVMatOfPoint4f(用于开始和结束坐标)或 OCVMatOfLine。你能帮我申报吗?
谢谢!
[/QUOTE]
这是一行
 

Attachments

  • Screenshot_20240412_145724.jpg
    Screenshot_20240412_145724.jpg
    463.2 KB · Views: 33

lingqdy1

Member
How to use the OCVVIDEOIO connection to play webcam or network video:mvideo.initialize(wz.text,movie.cap_any)

Is invalid


In OpenCV for Android (the "official") , VideoCapture is only related to video files, differently to what happens in OpenCV for windows where you can link it to a webcam, for instance. It is not a thing from my library, they simply did it this way: those parts that interact directly with hardware are in different modules (highgui for most of them, but not in Android). The API still exposes some initialization methods suitable for camera access, but they only make sense if you have special binary builds in which native camera is included.
So, for camera access, in Android you can use JavaCameraView (most of the released examples use it) or CameraEx (if you need more control of the camera, but examples get more complicated).
Anyway, I see that I should hide those methods that, even if exposed in the Java API, make no sense for the current build. Will do it in next release.

Please study the released examples and the advanced ones. I will be happy to assist you with any doubt you may have



Is this the original message or google translated? :eek:
如何使用OCVVIDEOIO连接播放网络摄像 头或网络视频:mvideo.initialize(wz.text,movie.cap_any)
Is invalid
 
Top