|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAs you all probably know, arrays are evil. Therefore, I've written a nice 1D/2D vector wrapper with matrix operations support, optimized with SSE for fast processing. It is useful in applications with matrix math where you have convolution, addition, subtraction, multiplication etc... of matrices with floating point precision. For example, I'm using it in neural networks, to support vector machine classifiers for computer vision programs. The class has been written with proper coding style, supporting read-only access, implemented with const-correctness. BackgroundYou should be familiar with matrices and the math behind them. Have a look at SOS math for a quick start. Have a look at the various SSE programming articles present here in the CodeProject as well. Using the codeFirst, make sure you've included the following headers in stdafx.h: #include <mm3dnow.h>
#include <float.h>
#include <time.h>
#include <math.h>
#include <windows.h>
#include <stdio.h>
The vector wrapper is presented with the
With the first constructor, you read the array from the file on the disk in text format: matrix.txt
2 3
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
The matrix.txt file provides a 2 by 3 matrix with all zero elements. Or, you can initialize the vector with the second constructor. If you do not provide any arguments to it, you have a 1 by 1 matrix, which is a scalar. The vec2D v1(1, 10); //is the 1x10 row vector
vec2D v2(10, 1); //is the 10x1 column vector
//this one initializes gaus_filter matrix with read-only access
const float gblur[] = { 0.0625f, 0.125f, 0.0625f,
0.125f, 0.25f, 0.125f,
0.0625f, 0.125f, 0.0625f };
const vec2D gaus_filter(3, 3, -1, -1, gblur);
float val = gaus_filter(0, 0); //val = 0.25f
With the following functions, you can access the first and the last available indices of the row and the column for the matrix:
You can access all the elements of the matrix this way: //Let's print out our gaus_filter;
for (int y = gaus_filter.yfirst(); y <= gaus_filter.ylast(); y++) {
for (int x = gaus_filter.xfirst(); x <= gaus_filter.xlast(); x++)
wprintf(L" %g", gaus_filter(y, x));
wprintf(L"\n");
}
Or you can do the same with:
If the file is not To get the sizes of the matrix, use the following functions:
To access the elements of the matrix, there are four overloaded operators present, with both read-write and read-only access:
With the //In Matlab we define the array like:
// v = zeros(3, 5);
//and we can print its contents with [] operator
// v[:]
//The same applies to [] overloaded operator
vec2D v(3, 5); //we have xfirst() and yfirst() equals to 0 as ordinary C array
for (unsigned int i = 0; i < v.length(); i++)
wprintf(L"%g\n", v[i]);
You can access the elements of the matrix also with:
It allows the indices to exceed the matrix dimensions. In that case, you will have a periodic boundary extension. So, if you have your first row and column indices equal to 0, and try to access With overloaded assignment operators, you can make a copy of the matrix, or initialize it with an external data buffer:
const float gblur[] = { 0.0625f, 0.125f, 0.0625f,
0.125f, 0.25f, 0.125f,
0.0625f, 0.125f, 0.0625f };
vec2D v1(3, 3);
v1 = gblur;
vec2D v2(3, 3);
vec2D v3(10, 5);
v2 = v1;
v3 = v2; //v3 will be resized to 3 by 3 matrix
With
The SSE optimized operationsThe following functions deal with SSE optimized math operations:
You can add, subtract, multiply, or divide all the matrix elements with a scalar. vec2D v(3, 5);
v.print();
v.add(3.4f);
v.print();
The functions for arithmetic operations on matrices are:
Where vec2D a(10, 10);
vec2D b = a;
vec2D c = a;
a.setrand();
b.setrand();
c.add(a, b); //c = a + b
a.print();
b.print();
c.print();
vec2D a(3, 5);
vec2D b(5, 2);
vec2D c(3, 2);
a.setrand();
b.setrand();
c.mul(a, b); //c = a * b
The SSE optimized matrices multiplication goes here:
The difference between //arrange transposed version of b for mult
vec2D a(3, 5);
vec2D b(2, 5);
vec2D c(3, 2);
a.setrand();
b.setrand();
c.mult(a, b); //c = a * b'; SSE optimized
a.print();
b.print();
c.print();
And, 2D convolution, normalization, and histogram equalizationThe other function useful in signal processing is convolution with a filter:
The first one is just convolution with a filter, and the second is convolution with a complex filter consisting of real and imaginary parts. //gaussian smoothing
vec2D v_original(100, 100);
vec2D v_smoothed = v_original;
v_smoothed.conv2D(v_original, gaus_filter);
//edge detection
const float Re[] = { 0.5f, 0.0f, -0.5f,
0.5f, 0.0f, -0.5f,
0.5f, 0.0f, -0.5f };
const float Im[] = { 0.5f, 0.5f, 0.5f,
0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f};
vec2D re(3, 3, -1, -1, Re);
vec2D im(3, 3, -1, -1, Im);
vec2D v_edges(100, 100);
//set the rectangle in the matrix to 0.0
//so there will be edges on the brim of it
RECT r(10, 10, 50, 50);
v_smoothed.set(0.0f, r);
v_edges.conv2D(v_smoothed, re, im);
The normalization and histogram equalization are used in image processing, for example, during a face detection process:
For normalization, the matrix is just normalized so its minimum value becomes For histogram equalization, provide an external row vector vec2D hist(1, 256);
vec2D v_heq(100, 100);
v_heq.setrand();
v_heq.norm(0.0f, 255.0f);
v_heq.histeq(hist);
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||