Discrete Fourier Transform

The Fourier Transform will decompose an image into its sinus and cosines components. It will transform an image from its spatial domain to its frequency domain. Mathematically a two dimensional images Fourier transform is:
F(k,l) = \displaystyle\sum\limits_{i=0}^{N-1}\sum\limits_{j=0}^{N-1} f(i,j)e^{-i2\pi(\frac{ki}{N}+\frac{lj}{N})}

e^{ix} = \cos{x} + i\sin {x}

Here f is the image value in its spatial domain and F in its frequency domain. The result of the transformation is complex numbers.

dft Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array.

void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)

Parameters:
  • src – input array that could be real or complex.
  • dst – output array whose size and type depends on the flags .
  • flags – transformation flags, representing a combination of the following values:
    • DFT_INVERSE performs an inverse 1D or 2D transform instead of the default forward transform.
    • DFT_SCALE scales the result: divide it by the number of array elements. Normally, it is combined with DFT_INVERSE.
    • DFT_ROWS performs a forward or inverse transform of every individual row of the input matrix; this flag enables you to transform multiple vectors simultaneously and can be used to decrease the overhead (which is sometimes several times larger than the processing itself) to perform 3D and higher-dimensional transformations and so forth.
    • DFT_COMPLEX_OUTPUT performs a forward transformation of 1D or 2D real array; the result, though being a complex array, has complex-conjugate symmetry (CCS, see the function description below for details), and such an array can be packed into a real array of the same size as input, which is the fastest option and which is what the function does by default; however, you may wish to get a full complex array (for simpler spectrum analysis, and so on) - pass the flag to enable the function to produce a full-size complex output array.
    • DFT_REAL_OUTPUT performs an inverse transformation of a 1D or 2D complex array; the result is normally a complex array of the same size, however, if the input array has conjugate-complex symmetry (for example, it is a result of forward transformation with DFT_COMPLEX_OUTPUT flag), the output is a real array; while the function itself does not check whether the input is symmetrical or not, you can pass the flag and then the function will assume the symmetry and produce the real output array (note that when the input is packed into a real array and inverse transformation is executed, the function treats the input as a packed complex-conjugate symmetrical array, and the output will also be a real array).
  • nonzeroRows – when the parameter is not zero, the function assumes that only the first nonzeroRows rows of the input array (DFT_INVERSE is not set) or only the first nonzeroRows of the output array (DFT_INVERSE is set) contain non-zeros, thus, the function can handle the rest of the rows more efficiently and save some time; this technique is very useful for calculating array cross-correlation or convolution using DFT.
void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)

Parameters:
  • src – input floating-point real or complex array.
  • dst – output array whose size and type depend on the flags.
  • flags – operation flags (same as dft()).
  • nonzeroRows – number of dst rows to process; the rest of the rows have undefined content

Example 1:

------------
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    // Read image from file
    // Make sure that the image is in grayscale
    Mat img = imread("lena.JPG",0);
    
    Mat planes[] = {Mat_<float>(img), Mat::zeros(img.size(), CV_32F)};
    Mat complexI;    //Complex plane to contain the DFT coefficients {[0]-Real,[1]-Img}
    merge(planes, 2, complexI);
    dft(complexI, complexI);  // Applying DFT

    // Reconstructing original imae from the DFT coefficients
    Mat invDFT, invDFTcvt;
    idft(complexI, invDFT, DFT_SCALE | DFT_REAL_OUTPUT ); // Applying IDFT
    invDFT.convertTo(invDFTcvt, CV_8U); 
    imshow("Output", invDFTcvt);

    //show the image
    imshow("Original Image", img);
    
    // Wait until user press some key
    waitKey(0);
    return 0;
}
------------

Example 2:

------------
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    // Read image from file
    // Make sure that the image is in grayscale
    Mat img = imread("lena.JPG",0);

    Mat dftInput1, dftImage1, inverseDFT, inverseDFTconverted;
    img.convertTo(dftInput1, CV_32F);
    dft(dftInput1, dftImage1, DFT_COMPLEX_OUTPUT);    // Applying DFT

    // Reconstructing original imae from the DFT coefficients
    idft(dftImage1, inverseDFT, DFT_SCALE | DFT_REAL_OUTPUT ); // Applying IDFT
    inverseDFT.convertTo(inverseDFTconverted, CV_8U);
    imshow("Output", inverseDFTconverted);

    //show the image
    imshow("Original Image", img);
    
    // Wait until user press some key
    waitKey(0);
    return 0;
}
------------

Sources:
http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#void%20dft%28InputArray%20src,%20OutputArray%20dst,%20int%20flags,%20int%20nonzeroRows%29

http://docs.opencv.org/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html

Crop elliptical region from image

We know that we can represent image as a matrix, and matrix can not be elliptical. So when you want to crop a elliptical area from an image, then you have to extract the elliptical region and remove rest of the information outside the ellipse. This can be done by AND operation of the image with an elliptical mask.

Steps:
  1. Read the image and convert to gray scale.
  2. Create the elliptical mask. ( use Negative argument to fill the ellipse)
    ellipse( im2, Point( 120, 130 ), Size( 50.0, 60.0 ), 0, 0, 360, Scalar( 255, 255, 255), -1, 8 );
  3. Use AND operation.
  4. Show the result.

Functions:

Example:

-------------
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include<conio.h>


using namespace cv;
using namespace std;

int main()
{
    Mat im1 = imread("Lena.jpg");
    if (im1.empty()) 
    {
        cout << "Cannot load image!" << endl;
        return -1;
    }
 cvtColor(im1, im1, CV_BGR2GRAY);
    imshow("im1", im1);  // Origina image
 
 Mat im2(im1.rows, im1.cols, CV_8UC1, Scalar(0,0,0));
 ellipse( im2, Point( 120, 130 ), Size( 50.0, 60.0 ), 0, 0, 360, Scalar( 255, 255, 255), -1, 8 );
 imshow("im2",im2);  // mask
 
 Mat res;
 bitwise_and(im1,im2,res);     
 imshow("AND",res);  // resultant image

    waitKey(0);
 return 0;
}
-------------
Result:

Calculating absolute values with scaling

void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0)
        - Scales, calculates absolute values, and converts the result to 8-bit.

Parameters:
  • src – input array.
  • dst – output array.
  • alpha – optional scale factor.
  • beta – optional delta added to the scaled values.
 You can find some applications here - Application1, Application2.


Window management in OpenCV


void namedWindow(const string&winname, int flags=WINDOW_AUTOSIZE )

Parameters:
  • name – Name of the window in the window caption that may be used as a window identifier.
  • flags – Flags of the window. Currently the only supported flag is CV_WINDOW_AUTOSIZE. If this is set, the window size is automatically adjusted to fit the displayed image, and you cannot change the window size manually.
  • CV_WINDOW_NORMAL - On Qt back end, you may use this to allow window resize. The image will resize itself according to the current window size. By using the | operator you also need to specify if you would like the image to keep its aspect ratio (CV_WINDOW_KEEPRATIO) or not (CV_WINDOW_FREERATIO). 

int waitKey(int delay=0)

Parameters: delay – Delay in milliseconds. 0 is the special value that means “forever”.

Click here for Examples.

Perspective Transform

Mat getPerspectiveTransform(InputArray src, InputArray dst)
- Calculates a perspective transform from four pairs of the corresponding points.

void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
- Applies a perspective transformation to an image.
Parameters:
  • src – input image.
  • dst – output image that has the size dsize and the same type as src .
  • M3\times 3 transformation matrix.
  • dsize – size of the output image.
  • flags – combination of interpolation methods (INTER_LINEAR or INTER_NEAREST) and the optional flag WARP_INVERSE_MAP, that sets M as the inverse transformation ( \texttt{dst}\rightarrow\texttt{src} ).
  • borderMode – pixel extrapolation method (BORDER_CONSTANT or BORDER_REPLICATE).
  • borderValue – value used in case of a constant border; by default, it equals 0.

Example:

------------
#include<opencv2/opencv.hpp>

using namespace cv;

int main( )
{
    // Input Quadilateral or Image plane coordinates
    Point2f inputQuad[4]; 
    // Output Quadilateral or World plane coordinates
    Point2f outputQuad[4];
        
    // Lambda Matrix
    Mat lambda( 2, 4, CV_32FC1 );
    //Input and Output Image;
    Mat input, output;
    
    //Load the image
    input = imread( "lena.jpg", 1 );
    // Set the lambda matrix the same type and size as input
    lambda = Mat::zeros( input.rows, input.cols, input.type() );

    // The 4 points that select quadilateral on the input , from top-left in clockwise order
    // These four pts are the sides of the rect box used as input 
    inputQuad[0] = Point2f( -30,-60 );
    inputQuad[1] = Point2f( input.cols+50,-50);
    inputQuad[2] = Point2f( input.cols+100,input.rows+50);
    inputQuad[3] = Point2f( -50,input.rows+50  );  
    // The 4 points where the mapping is to be done , from top-left in clockwise order
    outputQuad[0] = Point2f( 0,0 );
    outputQuad[1] = Point2f( input.cols-1,0);
    outputQuad[2] = Point2f( input.cols-1,input.rows-1);
    outputQuad[3] = Point2f( 0,input.rows-1  );

    // Get the Perspective Transform Matrix i.e. lambda 
    lambda = getPerspectiveTransform( inputQuad, outputQuad );
    // Apply the Perspective Transform just found to the src image
    warpPerspective(input,output,lambda,output.size() );

    //Display input and output
    imshow("Input",input);
    imshow("Output",output);

    waitKey(0);
    return 0;
}
------------

Result:


Rotate image

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

Parameters:
  • src – input image.
  • dst – output image that has the size dsize and the same type as src .
  • M2\times 3 transformation matrix.
  • dsize – size of the output image.
  • flags – combination of interpolation methods (see resize() ) and the optional flag WARP_INVERSE_MAP that means that M is the inverse transformation ( \texttt{dst}\rightarrow\texttt{src} ).
  • borderMode – pixel extrapolation method (see borderInterpolate()); when borderMode=BORDER_TRANSPARENT , it means that the pixels in the destination image corresponding to the “outliers” in the source image are not modified by the function.
  • borderValue – value used in case of a constant border; by default, it is 0.

The "rotate" function takes an image and returns the rotated image.

Example:

-----------
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat rotate(Mat src, double angle)
{
    Mat dst;
    Point2f pt(src.cols/2., src.rows/2.);    
    Mat r = getRotationMatrix2D(pt, angle, 1.0);
    warpAffine(src, dst, r, Size(src.cols, src.rows));
    return dst;
}

int main()
{
    Mat src = imread("lena.jpg");

    Mat dst;
    dst = rotate(src, 10);

    imshow("src", src);
    imshow("dst", dst);
    waitKey(0);
    return 0;
}
-----------

Result:


CAPTCHA formation in OpenCV

A CAPTCHA (an acronym for "Completely Automated Public Turing test to tell Computers and Humans Apart") is a type of challenge-response test used in computing to determine whether or not the user is human. It protects your website from spam by means of math logic, easily understood by human beings. You will not have to spend your precious time on annoying attempts to understand hard-to-read words, combinations of letters or pictures that make your eyes pop up.

I have borrowed this source code from here.

Example:

-----------
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <cstdlib>
#include <ctime>

using namespace cv;
using namespace std;

const Scalar WHITE = CV_RGB(255,255,255);
const int       CAPTCHA_LENGTH = 8;
const int         CHAR_HEIGHT = 100;
const int         CHAR_WIDTH  = 80;
const string     CHARACTERS[] = {"a", "A", "b", "B", "c", "C", "D", "d", "e", "E", "f", "F", "g", "G",
    "h", "H", "j", "J", "k", "K", "m", "M", "n", "N", "q", "Q", "R", "t", "T", "w", "W", "x", "X", "y", "Y",
    "1", "2", "3", "4", "5", "6", "7", "8", "9"};

void rotate(Mat &input, Mat &output) {

    int sign = rand() % 2;
    if ( sign == 0 ) {
        sign = -1;
    }

    int angle = ( rand() % 30 ) * sign; // between -30 and 30

    Point2f center(input.cols/2.0F, input.rows/2.0F);
    Mat rotationMatrix = getRotationMatrix2D(center, angle, 1.0);

    warpAffine(input, output, rotationMatrix, input.size(),
        INTER_LINEAR, BORDER_CONSTANT, WHITE);

}

void scale(Mat &input, Mat &output, float height, float width) {

    height = ( ( rand() % 20 ) * -1 ) + height;
    width  = ( ( rand() % 20 ) * -1 ) + width;

    Size s(width, height);
    cv::resize(input, output, s);
}

void addLines(Mat &image) {
    rand();
    RNG rng(rand());
    int numLines = CAPTCHA_LENGTH;
    for ( int i = 0; i < numLines; ++i) {
        int startX = rand() % image.cols;
        int endX = rand()   % image.cols;
        int startY = rand() % image.rows;
        int endY = rand()   % image.rows;

        cv::line(image,
            cv::Point(startX, startY),
            cv::Point(endX, endY),
            Scalar(rng.uniform(0, 256),rng.uniform(0, 256),rng.uniform(0, 256)),
            rng.uniform(0, 3), CV_AA); // anti-alias
    }
}

void transform(Mat &charImage) {

    cv::Point2f src[4];
    src[0] = cv::Point2f(0, 0);
    src[1] = cv::Point2f(0, CHAR_HEIGHT);
    src[2] = cv::Point2f(CHAR_WIDTH, 0);
    src[3] = cv::Point2f(CHAR_WIDTH, CHAR_HEIGHT);

    cv::Point2f dst[4];
    dst[0] = cv::Point2f(0, 0);
    dst[1] = cv::Point2f(0, CHAR_HEIGHT);
    dst[2] = cv::Point2f(CHAR_WIDTH, 0);

    int varWidth  = CHAR_WIDTH / 2;
    int varHeight = CHAR_HEIGHT / 2;
    int widthWarp  = CHAR_WIDTH - varWidth + (rand() % varWidth);
    int heightWarp = CHAR_HEIGHT - varHeight + (rand() % varHeight);
    dst[3] = cv::Point2f(widthWarp, heightWarp);

    Mat perspectiveTranx = cv::getPerspectiveTransform(src, dst);
    cv::warpPerspective(charImage, charImage, perspectiveTranx,
        cv::Size(charImage.cols, charImage.rows),
        INTER_CUBIC,
        BORDER_CONSTANT,
        WHITE);
}

void addNoise(Mat &image) {
    rand();
    RNG rng(rand());
    int i,j;
    for (int n = 0; n < 100; n++) {

        i= rand() % image.cols;
        j= rand() % image.rows;

        Point center(i, j);
        circle(image, center, rng.uniform(1, 3),     // radius,
            Scalar(rng.uniform(0, 256),rng.uniform(0, 256),rng.uniform(0, 256)),  // color of noise points
            -2,                  // thickness, negative for filled
            CV_AA);                
    }
}

int main(int argc, char *argv[])
{
    int charactersSize = sizeof(CHARACTERS) / sizeof(CHARACTERS[0]);

    Mat outImage(CHAR_HEIGHT, CHAR_WIDTH * CAPTCHA_LENGTH, CV_8UC3, WHITE);

    srand((unsigned)time(0));
    rand();
    RNG rng(rand());

    
    Scalar color = CV_RGB(0, 0, 0); //255, 127, 80);

    for ( int i = 0; i < CAPTCHA_LENGTH; ++i ) {
        cv::Mat charImage(CHAR_HEIGHT, CHAR_WIDTH, CV_8UC3, WHITE);

        string c = CHARACTERS[rand() % charactersSize];

        putText(charImage, c, Point(10, CHAR_HEIGHT - 10), rng.uniform(1, 6), rng.uniform(3.0, 4.0), color, rng.uniform(1, 5), CV_AA);
        imshow("1st look",charImage);
        transform(charImage);
        imshow("transform",charImage);
        rotate(charImage, charImage);
        imshow("rotate",charImage);
        scale(charImage, charImage, CHAR_HEIGHT, CHAR_WIDTH);
        imshow("scale",charImage);

        charImage.copyTo(outImage(cv::Rect(CHAR_WIDTH * i, 0, charImage.cols, charImage.rows)));
        //waitKey(0);
    }

    addLines(outImage);
    addNoise(outImage);
    double a = rng.uniform(0, 2);
    cout<<"   "<<a<<endl;
    imshow("Captcha11", outImage);
    waitKey(0);

    return EXIT_SUCCESS;
}
-----------

Result:



Sources:
http://en.wikipedia.org/wiki/CAPTCHA