Wednesday, November 6, 2019

[OpenCV Tutorial] $1 - Image Processing (imgproc module) | Lession 1 - Eroding and Dilating

Goal

In this tutorial you will learn how to:
  • Apply two very common morphology operators: Dilation and Erosion. For this purpose, you will use the following OpenCV functions:

Cool Theory

Note
The explanation below belongs to the book Learning OpenCV by Bradski and Kaehler.

Morphological Operations

  • In short: A set of operations that process images based on shapes. Morphological operations apply a structuring element to an input image and generate an output image.
  • The most basic morphological operations are two: Erosion and Dilation. They have a wide array of uses, i.e. :
    • Removing noise
    • Isolation of individual elements and joining disparate elements in an image.
    • Finding of intensity bumps or holes in an image
  • We will explain dilation and erosion briefly, using the following image as an example:
    Morphology_1_Tutorial_Theory_Original_Image.png

Dilation

  • This operations consists of convoluting an image A with some kernel ( B), which can have any shape or size, usually a square or circle.
  • The kernel B has a defined anchor point, usually being the center of the kernel.
  • As the kernel B is scanned over the image, we compute the maximal pixel value overlapped by B and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to "grow" (therefore the name dilation). Take as an example the image above. Applying dilation we can get:
    Morphology_1_Tutorial_Theory_Dilation.png
The background (bright) dilates around the black regions of the letter.
To better grasp the idea and avoid possible confusion, in this another example we have inverted the original image such as the object in white is now the letter. We have performed two dilatations with a rectangular structuring element of size 3x3.
Morphology_1_Tutorial_Theory_Dilatation_2.png
Left image: original image inverted, right image: resulting dilatation
The dilatation makes the object in white bigger.

Erosion

  • This operation is the sister of dilation. What this does is to compute a local minimum over the area of the kernel.
  • As the kernel B is scanned over the image, we compute the minimal pixel value overlapped by B and replace the image pixel under the anchor point with that minimal value.
  • Analagously to the example for dilation, we can apply the erosion operator to the original image (shown above). You can see in the result below that the bright areas of the image (the background, apparently), get thinner, whereas the dark zones (the "writing") gets bigger.
    Morphology_1_Tutorial_Theory_Erosion.png
In the same manner, the corresponding image resulting of the erosion operation on the inverted original image (two erosions with a rectangular structuring element of size 3x3):
Morphology_1_Tutorial_Theory_Erosion_2.png
Left image: original image inverted, right image: resulting erosion
The erosion makes the object in white smaller.

Code

This tutorial code's is shown lines below. You can also download it from here
using namespace cv;
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
void Erosion( int, void* );
void Dilation( int, void* );
int main( int, char** argv )
{
src = imread( argv[1], IMREAD_COLOR );
if( src.empty() )
{ return -1; }
namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
moveWindow( "Dilation Demo", src.cols, 0 );
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
&erosion_elem, max_elem,
Erosion );
createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",
&erosion_size, max_kernel_size,
Erosion );
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
&dilation_elem, max_elem,
Dilation );
createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",
&dilation_size, max_kernel_size,
Dilation );
Erosion( 0, 0 );
Dilation( 0, 0 );
waitKey(0);
return 0;
}
void Erosion( int, void* )
{
int erosion_type = 0;
if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
erode( src, erosion_dst, element );
imshow( "Erosion Demo", erosion_dst );
}
void Dilation( int, void* )
{
int dilation_type = 0;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( dilation_type,
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst );
}

Explanation

  1. Most of the stuff shown is known by you (if you have any doubt, please refer to the tutorials in previous sections). Let's check the general structure of the program:
    • Load an image (can be BGR or grayscale)
    • Create two windows (one for dilation output, the other for erosion)
    • Create a set of two Trackbars for each operation:
      • The first trackbar "Element" returns either erosion_elem or dilation_elem
      • The second trackbar "Kernel size" return erosion_size or dilation_size for the corresponding operation.
    • Every time we move any slider, the user's function Erosion or Dilation will be called and it will update the output image based on the current trackbar values.
    Let's analyze these two functions:
  2. erosion:
    void Erosion( int, void* )
    {
    int erosion_type = 0;
    if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
    else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
    else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
    Mat element = getStructuringElement( erosion_type,
    Size( 2*erosion_size + 1, 2*erosion_size+1 ),
    Point( erosion_size, erosion_size ) );
    erode( src, erosion_dst, element );
    imshow( "Erosion Demo", erosion_dst );
    }
    • The function that performs the erosion operation is cv::erode . As we can see, it receives three arguments:
      • src: The source image
      • erosion_dst: The output image
      • element: This is the kernel we will use to perform the operation. If we do not specify, the default is a simple 3x3 matrix. Otherwise, we can specify its shape. For this, we need to use the function cv::getStructuringElement :
        Mat element = getStructuringElement( erosion_type,
        Size( 2*erosion_size + 1, 2*erosion_size+1 ),
        Point( erosion_size, erosion_size ) );
        We can choose any of three shapes for our kernel:
        • Rectangular box: MORPH_RECT
        • Cross: MORPH_CROSS
        • Ellipse: MORPH_ELLIPSE
        Then, we just have to specify the size of our kernel and the anchor point. If not specified, it is assumed to be in the center.
    • That is all. We are ready to perform the erosion of our image.
      Note
      Additionally, there is another parameter that allows you to perform multiple erosions (iterations) at once. We are not using it in this simple tutorial, though. You can check out the Reference for more details.
  3. dilation:
    The code is below. As you can see, it is completely similar to the snippet of code for erosion. Here we also have the option of defining our kernel, its anchor point and the size of the operator to be used.
    void Dilation( int, void* )
    {
    int dilation_type = 0;
    if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
    else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
    else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
    Mat element = getStructuringElement( dilation_type,
    Size( 2*dilation_size + 1, 2*dilation_size+1 ),
    Point( dilation_size, dilation_size ) );
    dilate( src, dilation_dst, element );
    imshow( "Dilation Demo", dilation_dst );
    }

    Results

Compile the code above and execute it with an image as argument. For instance, using this image:
Morphology_1_Tutorial_Original_Image.jpg
We get the results below. Varying the indices in the Trackbars give different output images, naturally. Try them out! You can even try to add a third Trackbar to control the number of iterations.
Morphology_1_Result.jpg

Friday, October 25, 2019

[Fix CMAKE Configure Error] Detecting CXX compiler ABI info - failed

I use Cmake to generate code for OpenCV...
After finish configure..The it fail..

The direction of Cmake in E:\ Disk.

The CXX compiler identification is GNU 4.9.2
The C compiler identification is GNU 4.9.2
Check for working CXX compiler: C:/mingw64/mingw64/bin/x86_64-w64-mingw32-g++.exe
Check for working CXX compiler: C:/mingw64/mingw64/bin/x86_64-w64-mingw32-g++.exe -- works
Detecting CXX compiler ABI info
Detecting CXX compiler ABI info - failed
Detecting CXX compile features

Detecting CXX compile features - done


Detecting CXX compiler ABI info - failed????

So I have moved Cmake Folder to C:\ Folder.. And Done.

Sunday, October 20, 2019

[ Fix QT Creator ] ASSERT: "!"No style available without QApplication!"" in file kernel\qapplication.cpp

Error (windows and ubuntu with last qt 5.7). I created qt quick 2 controls app, add chart 2d bar and try run project, but I've got an error.

File main.c 

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
...
}

How to Fix it???

Easy to Fix... 

Maybe in this version,It doesn't support QGuiApplication.. 

So,you have to instead use QApplication..

1. Add widgets to file .pro to use QApplication
QT += quick widgets

2. in main.c change to use QApplication

#include <QApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc,argv);
...
}

Thursday, October 17, 2019

[ Linux Threading ] Thread - POSIX Libary

POSIX thread (pthread) libraries
The POSIX thread libraries are a standards based thread API for C/C++. It allows one to spawn a new concurrent process flow. It is most effective on multi-processor or multi-core systems where the process flow can be scheduled to run on another processor thus gaining speed through parallel or distributed processing. Threads require less overhead than "forking" or spawning a new process because the system does not initialize a new system virtual memory space and environment for the process. While most effective on a multiprocessor system, gains are also found on uniprocessor systems which exploit latency in I/O and other system functions which may halt process execution. (One thread may execute while another is waiting for I/O or some other system latency.) Parallel programming technologies such as MPI and PVM are used in a distributed computing environment while threads are limited to a single computer system. All threads within a process share the same address space. A thread is spawned by defining a function and its arguments which will be processed in the thread. The purpose of using the POSIX thread library in your software is to execute software faster.


Thread Basics:
Thread operations include thread creation, termination, synchronization (joins,blocking), scheduling, data management and process interaction.
A thread does not maintain a list of created threads, nor does it know the thread that created it.
All threads within a process share the same address space.
Threads in the same process share:

  • Process instructions
  • Most data
  • open files (descriptors)
  • signals and signal handlers
  • current working directory
  • User and group id

Each thread has a unique:

  • Thread ID
  • set of registers, stack pointer
  • stack for local variables, return addresses
  • signal mask
  • priority
  • Return value: errno

pthread functions return "0" if OK.


Thread Creation and Termination:

Example: pthread1.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message_function( void *ptr );

main()
{
     pthread_t thread1, thread2;
     const char *message1 = "Thread 1";
     const char *message2 = "Thread 2";
     int  iret1, iret2;

    /* Create independent threads each of which will execute function */

     iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);

     if(iret1)
     {
         fprintf(stderr,"Error - pthread_create() return code: %d\n",iret1);
         exit(EXIT_FAILURE);
     }

     iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);
     if(iret2)
     {
         fprintf(stderr,"Error - pthread_create() return code: %d\n",iret2);
         exit(EXIT_FAILURE);
     }

     printf("pthread_create() for thread 1 returns: %d\n",iret1);
     printf("pthread_create() for thread 2 returns: %d\n",iret2);

     /* Wait till threads are complete before main continues. Unless we  */
     /* wait we run the risk of executing an exit which will terminate   */
     /* the process and all threads before the threads have completed.   */

     pthread_join( thread1, NULL);

     pthread_join( thread2, NULL);

     exit(EXIT_SUCCESS);
}

void *print_message_function( void *ptr )
{
     char *message;
     message = (char *) ptr;
     printf("%s \n", message);
}



Compile:

C compiler: cc -pthread pthread1.c (or cc -lpthread pthread1.c)
or
C++ compiler: g++ -pthread pthread1.c (or g++ -lpthread pthread1.c)
The GNU compiler now has the command line option "-pthread" while older versions of the compiler specify the pthread library explicitly with "-lpthread".
Run: ./a.out

Results:
Thread 1
Thread 2
Thread 1 returns: 0
Thread 2 returns: 0

Details:











Thread Synchronization:
The threads library provides three synchronization mechanisms:

1.mutexes - Mutual exclusion lock: Block access to variables by other threads. This enforces exclusive access by a thread to a variable or set of variables.
joins - Make a thread wait till others are complete (terminated).
condition variables - data type pthread_cond_t



If register load and store operations for the incrementing of variable counter occurs with unfortunate timing (maybe call as interrupt or higher priority thread) , it is theoretically possible to have each thread increment and overwrite the same variable with the same value. Another possibility is that thread two would first increment counter locking out thread one until complete and then thread one would increment it to 2.



Mutexes:
Mutexes are used to prevent data inconsistencies due to operations by multiple threads upon the same memory area performed at the same time or to prevent race conditions where an order of operation upon the memory is expected. A contention or race condition often occurs when two or more threads need to perform operations on the same memory area, but the results of computations depends on the order in which these operations are performed. Mutexes are used for serializing shared resources such as memory. Anytime a global resource is accessed by more than one thread the resource should have a Mutex associated with it. One can apply a mutex to protect a segment of memory ("critical region") from other threads. Mutexes can be applied only to threads in a single process and do not work between processes as do semaphores.

Example threaded function:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *functionC();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int  counter = 0;

main()
{
   int rc1, rc2;
   pthread_t thread1, thread2;
   /* Create independent threads each of which will execute functionC */

   if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
   {
      printf("Thread creation failed: %d\n", rc1);
   }

   if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) )
   {
      printf("Thread creation failed: %d\n", rc2);
   }

   /* Wait till threads are complete before main continues. Unless we  */
   /* wait we run the risk of executing an exit which will terminate   */
   /* the process and all threads before the threads have completed.   */

   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   exit(EXIT_SUCCESS);
}

void *functionC()
{
   pthread_mutex_lock( &mutex1 );
   counter++;
   printf("Counter value: %d\n",counter);
   pthread_mutex_unlock( &mutex1 );
}


Compile: cc -pthread mutex1.c (or cc -lpthread mutex1.c for older versions of the GNU compiler which explicitly reference the library)
Run: ./a.out

Results:

Counter value: 1
Counter value: 2

When a mutex lock is attempted against a mutex which is held by another thread, the thread is blocked until the mutex is unlocked. When a thread terminates, the mutex does not unless explicitly unlocked. Nothing happens by default.

Man Pages:
  • pthread_mutex_lock() - acquire a lock on the specified mutex variable. If the mutex is already locked by another thread, this call will block the calling thread until the mutex is unlocked.
  • pthread_mutex_unlock() - unlock a mutex variable. An error is returned if mutex is already unlocked or owned by another thread.
  • pthread_mutex_trylock() - attempt to lock a mutex or will return error code if busy. Useful for preventing deadlock conditions.

2.Joins:

A join is performed when one wants to wait for a thread to finish. A thread calling routine may launch multiple threads then wait for them to finish to get the results. One waits for the completion of the threads with a join.

Sample code: join1.c


#include <stdio.h>
#include <pthread.h>

#define NTHREADS 10
void *thread_function(void *);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int  counter = 0;

main()
{
   pthread_t thread_id[NTHREADS];
   int i, j;

   for(i=0; i < NTHREADS; i++)
   {
      pthread_create( &thread_id[i], NULL, thread_function, NULL );
   }

   for(j=0; j < NTHREADS; j++)
   {
      pthread_join( thread_id[j], NULL);
   }

   /* Now that all threads are complete I can print the final result.     */
   /* Without the join I could be printing a value before all the threads */
   /* have been completed.                                                */

   printf("Final counter value: %d\n", counter);
}

void *thread_function(void *dummyPtr)
{
   printf("Thread number %ld\n", pthread_self());
   pthread_mutex_lock( &mutex1 );
   counter++;
   pthread_mutex_unlock( &mutex1 );
}


Compile: g++ join.cpp -lpthread
Run: ./a.out
Results:

Thread number 1026
Thread number 2051
Thread number 3076
Thread number 4101
Thread number 5126
Thread number 6151
Thread number 7176
Thread number 8201
Thread number 9226
Thread number 10251
Final counter value: 10

Tuesday, October 15, 2019

[Fix QT] TLS initialization failed | QSslSocket::connectToHostEncrypted Fail

The solution of TLS initialization failed step by step:

1- Firstly you need to find your SSL version for your windows machine( SSL version strictly depends on QT versions) with this function:
#include <QCoreApplication>
#include <QDebug>
#include <QSslSocket> //To use QSslSocket Class

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug()<<QSslSocket::supportsSsl() << QSslSocket::sslLibraryBuildVersionString() << QSslSocket::sslLibraryVersionString();
    return a.exec();
}
Result: 
2- After that run your code and call the above function. It will print your required SSL version in application output. In my case, it was “OpenSSL 1.0.2p 14 Aug 2018” “” which may be different for all the users.
3- TLS initialization failed: Now Download the requires SSL libraries from the link given below:
In my case: I download openssl-1.0.2p-x64_86-win64.zip
4- Paste all the files/content of SSL folder (which you have extracted) into the  debug folder. for eg: In my case it is:
E:\QT\NebProject\NASA_Vision\build-NASA_Vision-Desktop_Qt_5_12_2_MSVC2015_64bit-Debug\debug
Ok...Done
Back to Top