During coding some pixel manipulation class, I have implemented non max suppression function.
Code is here:
signed char * nonMaxSuppress(int windowSize, signed char * pointer) {
int delta = windowSize / 2;
int index;
int counter = 0;
signed char current;
for(int row = 3; row < GLOBAL_HEIGHT - 3; ++row)
{
for(int col = 3; col < GLOBAL_WIDTH - 3; ++col)
{
counter = 0;
current = pointer[(row * GLOBAL_WIDTH) + col];
for(int i = 0; i < windowSize; ++i)
{
for(int j = 0; j < windowSize; ++j)
{
index = ((row - delta + i) * GLOBAL_WIDTH) + (col - delta + j);
if(current > pointer[index]) {
counter++;
}
}
}
if(counter != ((windowSize * windowSize) - 1)){
pointer[(row * GLOBAL_WIDTH) + col] = 0;
}
}
}
return pointer;}
Now the resulting picture before and after non max suppression is quite weird.
It feels like some line started to appear out of the blue.
Please watch attached pictures (Before and After non max suppression).
I will be thankful in case of any help.
Thx!
Please ignore the 3 pixels error i have in the edge of the images and just for you knowledge those image after grayscale and Diffrence Of Gaussian
Can you see the added lines? What is it?
You are trying to perform the suppression inplace. Consider the pixel (col, row). Once you modify its contents the next pixel (col+1, row) will have a different windowSize*windowSize neighbourhood.
To fix this problem you have to use another array as an output. Just replace
if(counter != ((windowSize * windowSize) - 1)){
pointer[(row * GLOBAL_WIDTH) + col] = 0;
}
with
output[(row * GLOBAL_WIDTH) + col] =
(counter != ((windowSize * windowSize) - 1)) ? 0 : current;
Related
I have this code that implements Prewitt edge detection. What I need to do is to implement it with only one buffer, meaning, I will not create copy of the image but edit original image. So if i want to change pixel with value 78, I cant put the new value e.g. 100 until all surrounding pixels have read value 78. Color values of the pixels. I have tried all day to figure it out but couldn't, if someone would write me some kind of pseudocode I would be very grateful
void filter_serial_prewitt(int *inBuffer, int *outBuffer, int width, int height){
for (int i = 1; i < width - 1; i ++) {
for (int j = 1; j < height - 1; j ++) {
int Fx = 0;
int Fy = 0;
int F = 0;
for (int m = -1; m <= 1; m++) {
for (int n = -1; n <= 1; n++) {
Fx += inBuffer[(j + n) * width + (i + m)] * n;
Fy += inBuffer[(j + n) * width + (i + m)] * m;
}
}
F = abs(Fx) + abs(Fy);
if (F < THRESHOLD){
outBuffer[j * width + i] = 255;
} else{
outBuffer[j * width + i] = 0;
}
}
}
}
One thing to know about a Prewitt operator is that it is separable. See the Wikipedia article for details.
To calculate a single output row, you need to do the following (pseudocode):
int* buffer = malloc (sizeof(int) * width);
for (int i = 0; i < width; i++)
{
// Do the vertical pass of the convolution of the first 3 rows into
// the buffer.
buffer [ i ] = vertical_convolve(inBuffer [ i ], vertical_kernel);
}
// Next, do the horizontal convolution of the first row. We need to
// keep the previous value in a temp buffer while we work
int temp0 = horizontal_convolve(buffer [ 0 ], horizontal_kernel);
for (int i = 1; i < width; i++)
{
int temp1 = horizontal_convolve(buffer[ i ], horizontal_kernel);
inBuffer [ i - 1 ] = temp0;
temp0 = temp1;
}
That requires a buffer that is 1 pixel tall and the width of the image.
To work on the whole image, you need to keep 2 of the above buffers around and after you calculate a pixel on the third line, you can replace the first pixel of the first line of the image with the first pixel of the first buffer. Then you can put the newly calculated value into the buffer.
So in this scenario, you won't keep around an entire second image, but will need to keep around 2 1-pixel tall buffers that are as wide as the image.
I am trying to make an alphatrimmed filter in openCV library. My code is not working properly and the resultant image is not looking as image after filtering.
The filter should work in the following way.
Chossing some (array) of pixels in my example it is 9 pixels '3x3' window.
Ordering them in increasing way.
Cutting our 'array' both sides for alpha-2.
calculating arithmetic mean of remaining pixels and inserting them in proper place.
int alphatrimmed(Mat img, int alpha)
{
Mat img9 = img.clone();
const int start = alpha/2 ;
const int end = 9 - (alpha/2);
//going through whole image
for (int i = 1; i < img.rows - 1; i++)
{
for (int j = 1; j < img.cols - 1; j++)
{
uchar element[9];
Vec3b element3[9];
int k = 0;
int a = 0;
//selecting elements for window 3x3
for (int m = i -1; m < i + 2; m++)
{
for (int n = j - 1; n < j + 2; n++)
{
element3[a] = img.at<Vec3b>(m*img.cols + n);
a++;
for (int c = 0; c < img.channels(); c++)
{
element[k] += img.at<Vec3b>(m*img.cols + n)[c];
}
k++;
}
}
//comparing and sorting elements in window (uchar element [9])
for (int b = 0; b < end; b++)
{
int min = b;
for (int d = b + 1; d < 9; d++)
{
if (element[d] < element[min])
{
min = d;
const uchar temp = element[b];
element[b] = element[min];
element[min] = temp;
const Vec3b temporary = element3[b];
element3[b] = element3[min];
element3[min] = temporary;
}
}
}
// index in resultant image( after alpha-trimmed filter)
int result = (i - 1) * (img.cols - 2) + j - 1;
for (int l = start ; l < end; l++)
img9.at<Vec3b>(result) += element3[l];
img9.at<Vec3b>(result) /= (9 - alpha);
}
}
namedWindow("AlphaTrimmed Filter", WINDOW_AUTOSIZE);
imshow("AlphaTrimmed Filter", img9);
return 0;
}
Without actual data, it's somewhat of a guess, but an uchar can't hold the sum of 3 channels. It works modulo 256 (at least on any platform OpenCV supports).
The proper solution is std::sort with a proper comparator for your Vec3b :
void L1(Vec3b a, Vec3b b) { return a[0]+a[1]+a[2] < b[0]+b[1]+b[2]; }
I am building a game of life CA in C++ (openFrameworks). As I am new to C++ I was wondering if someone could let me know if I am setting up the vectors correctly in the following code. the CA does not draw to the screen and I am not sure if this is as a result of how I set up the vectors. I have to use 1D vectors as I intend to send data to Pure Data which only handles 1D structures.
GOL::GOL() {
init();
}
void GOL::init() {
for (int i =1;i < cols-1;i++) {
for (int j =1;j < rows-1;j++) {
board.push_back(rows * cols);
board[i * cols + j] = ofRandom(2);
}
}
}
void GOL::generate() {
vector<int> next(rows * cols);
// Loop through every spot in our 2D array and check spots neighbors
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
// Add up all the states in a 3x3 surrounding grid
int neighbors = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
neighbors += board[((x+i+cols)%cols) * cols + ((y+j+rows)%rows)];
}
}
// A little trick to subtract the current cell's state since
// we added it in the above loop
neighbors -= board[x * cols + y];
// Rules of Life
if ((board[x * cols + y] == 1) && (neighbors < 2)) next[x * cols + y] = 0; // Loneliness
else if ((board[x * cols + y] == 1) && (neighbors > 3)) next[x * cols + y] = 0; // Overpopulation
else if ((board[x * cols + y] == 0) && (neighbors == 3)) next[x * cols + y] = 1; // Reproduction
else next[x * cols + y] = board[x * cols + y]; // Stasis
}
}
// Next is now our board
board = next;
}
this looks weird in your code:
void GOL::init() {
for (int i =1;i < cols-1;i++) {
for (int j =1;j < rows-1;j++) {
board.push_back(rows * cols);
board[i * cols + j] = ofRandom(2);
}
}
}
"vector.push_back( value )" means "append value to the end of this vector" see std::vector::push_back reference
After doing this, you access the value of board[i * cols + j] and change it into a random value. What I think you are trying to do is:
void GOL::init() {
// create the vector with cols * rows spaces:
for(int i = 0; i < cols * rows; i++){
board.push_back( ofRandom(2));
}
}
This is how you would access every element at position x,y in your vector:
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
board[x * cols + y] = blabla;
}
}
This means that in void GOL::generate() you are not accessing the right position when you do this:
neighbors += board[((x+i+cols)%cols) * cols + ((y+j+rows)%rows)];
I think you want to do this:
neighbors += board[((x+i+cols)%cols) * rows + ((y+j+rows)%rows)];
so x * rows + y instead of x * cols + y
Suppose i have an image matrix and i am at a particular pixel [say 4] like this:
0 1 2
3 `4` 5
6 7 8
I am trying to cycle through all pixels and am attempting to access 0,1,2, 3,5 6,7,8 whose values i am storing in the array called Pixel.... here is my attempt at it using OpenCV, kindly tell me where am i going wrong.
I am using pointer temp_ptr to access the IplImage image.
uchar* temp_ptr=0 ;
CvScalar Pixel[3][3];
int rows=image->height,cols=image->width,row,col;
for( row = 0; row < rows-2; ++row)
{
for ( col = 0; col < cols-2; ++col)
{
temp_ptr = &((uchar*)(image->imageData + (image->widthStep*row)))[col*3];
for (int krow = -1 ; krow <= 1; krow++)
{
for (int kcol = -1; kcol <= 1; kcol++)
{
temp_ptr = &((uchar*)(image->imageData + (image->widthStep*row+krow)))[(col+kcol)*3];
for(int i=0; i < 3; i++)
{
for(int j=0; j < 3; j++)
{
for(int k=0; k < 3; k++)
{
Pixel[i][j].val[k]=temp_ptr[k];
}
}
}
}
}
}
}
I am not really sure how to load the sorrounding Pixels usingtemp_ptr, please help me out.
Well sir, it sounds like you want to do convolution, and doing it this way when you have OpenCV at your fingertips is a bit like hammering a can opener on your Spaghettios to burst it open by blunt force.
In fact, what you're doing is almost exactly the output of cv::blur(src, dst, cv::Size(3,3)) except it also includes the center pixel in the average.
If you want to exclude the center pixel then you can create a custom kernel - just a matrix with appropriate weights:
[.125 .125 .125
.125 0 .125
.125 .125 .125 ]
and apply this to the image with cv::filter2d(src, dst, -1, kernel).
Assuming image->imageData is in RGB format, so there are 3 bytes for each pixel, you could do something like this:
int rows = image->height;
int cols = image->width;
uchar* temp_ptr = 0;
CvScalar pixels[8];
for (int col = 0; col < image->height - 2; col++) {
temp_ptr = image->imageData + image->width * col + 1;
for (int row = 0; row < image->width - 2; row++) {
temp_ptr += row * 3;
pixels[0].val = temp_ptr - width * 3 - 3; // pixel 0 from your example
pixels[1].val = temp_ptr - width * 3; // 1
pixels[2].val = temp_ptr - width * 3 + 3; // 2
pixels[3].val = temp_ptr - 3; // 4
pixels[4].val = temp_ptr + 3; // etc...
pixels[5].val = temp_ptr + width * 3 - 3;
pixels[6].val = temp_ptr + width * 3;
pixels[7].val = temp_ptr + width * 3 + 3;
// calculate averages here and store them somewhere (in a vector perhaps)
}
}
Note I didn't test this code.
First of all you have to start learning some programming. Your complete code is a mess.
Some major problems I could quickly found:
First of all you have to start your first two for loops from 1 (because you decrement by -1 when you apply the window) and you will end up reading some memory address that are not allocated.
Second the first temp_ptr = &((uchar*)(image->imageData + (image->widthStep*row)))[col*3] is useless so you can remove it.
the other
temp_ptr = &((uchar*)(image->imageData + (image->widthStep*row+krow)))[(col+kcol)*3];
is having a small problem, the operator precedence, should be:
temp_ptr = &((uchar*)(image->imageData + image->widthStep*(row+krow))[(col+kcol)*3];
you don't need the other 3 inside loops
Also is not clear what you want to do, you want to get the neighborhood of a specific pixel (then you need no loops) or you want to apply a kernel to each pixel from the image.
I wrote the following, but I'm not understanding it after modifying it some to fit with single pixels (graphic displays) instead of single characters (character displays).
XRES x YRES is the pixel resolution of each character. LCDGraphic draws its own characters based on these values. The idea in this transition algorithm is that you can go right, left, or (both) right one line, left the next line, then right, etc... The text version works like it's supposed to, but when I translated it for graphic displays, it's acting weird.
LCOLS is 256 (the sentinal), and transition_tick_ increments till this sentinel each time LCDGraphic::Transition() is executed. col can thus be in the range between 0-255. Well, when pixels are going left and right, they're supposed to be moving together. However, for some reason the lines going right move till they're finished, then the lines moving left move till they're finished. It appears that where col is < 128 the left moving lines are adjusting, then when col is >= 128 the right moving lines adjust. I'm pretty well confused by this.
void LCDGraphic::Transition() {
int direction = visitor_->GetDirection();
int col;
transitioning_ = true;
for(unsigned int row = 0; row < LROWS / YRES; row++) {
if( direction == TRANSITION_LEFT ||
(direction == TRANSITION_BOTH && row % 2 == 0))
col = LCOLS - transition_tick_;
else if( direction == TRANSITION_RIGHT || direction == TRANSITION_BOTH)
col = transition_tick_;
else
col = 0;
if(col < 0)
col = 0;
for(unsigned int i = 0; i < YRES; i++) {
int n = row * YRES * LCOLS + i * LCOLS;
for(unsigned int l = 0; l < 1; l++) {// LAYERS; l++) {
RGBA tmp[LCOLS];
memcpy(tmp + XRES, GraphicFB[l] + n + col + XRES, (LCOLS - col) * sizeof(RGBA));
for(unsigned j = 0; j < XRES; j++)
tmp[j] = NO_COL;
memcpy(GraphicFB[l] + n + col, tmp, sizeof(RGBA) * (LCOLS - col));
}
}
}
transition_tick_+=XRES;
if( transition_tick_ >= (int)LCOLS ) {
transitioning_ = false;
transition_tick_ = 0;
emit static_cast<LCDEvents *>(
visitor_->GetWrapper())->_TransitionFinished();
}
GraphicBlit(0, 0, LROWS, LCOLS);
}
I figured it out. Just half LCOLS. Odd problem though. I'm still a bit confused.
void LCDGraphic::Transition() {
int direction = visitor_->GetDirection();
int col;
transitioning_ = true;
for(unsigned int row = 0; row < LROWS / YRES; row++) {
if( direction == TRANSITION_LEFT ||
(direction == TRANSITION_BOTH && row % 2 == 0))
col = LCOLS / 2 - transition_tick_; // changed this line
else if( direction == TRANSITION_RIGHT || direction == TRANSITION_BOTH)
col = transition_tick_;
else
col = 0;
if(col < 0)
col = 0;
for(unsigned int i = 0; i < YRES; i++) {
int n = row * YRES * LCOLS + i * LCOLS;
for(unsigned int l = 0; l < 1; l++) {// LAYERS; l++) {
RGBA tmp[LCOLS];
LCDError("Transition: LROWS: %u, LCOLS: %u, n: %d, row: %d, col: %d, calc1: %d, calc2: %d, fb: %p, tmp: %p",
LROWS, LCOLS, n, row, col, n + col + XRES, (LCOLS - col) * sizeof(RGBA), GraphicFB, tmp);
memcpy(tmp + XRES, GraphicFB[l] + n + col + XRES, (LCOLS - col) * sizeof(RGBA));
for(unsigned j = 0; j < XRES; j++)
tmp[j] = NO_COL;
memcpy(GraphicFB[l] + n + col, tmp, sizeof(RGBA) * (LCOLS - col));
}
}
}
transition_tick_+=XRES;
if( transition_tick_ >= (int)LCOLS / 2) { //changed this line
transitioning_ = false;
transition_tick_ = 0;
emit static_cast<LCDEvents *>(
visitor_->GetWrapper())->_TransitionFinished();
}
GraphicBlit(0, 0, LROWS, LCOLS);
}