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.
Related
I'm trying to write some C++ to create a 1048x1048x8 bit matrix of 256x256 squares. The first should have a grey scale value of 0 while the last should be 255. This is what I've tried so far. Any feedback is appreciated.
First image is my result. Second is the desired.
[1]: https://i.stack.imgur.com/BmGOZ.png
[2]: https://i.stack.imgur.com/FMpi1.png
using namespace std;
#include <fstream>
#include <iostream>
int main()
{
char img[256][256];
ofstream binaryFile("file.raw", ios::out | ios::binary);
if (!binaryFile) {
cout << "cannot create file";
return 1;
}
//create raw file
char color = 0;
//nested for loops to iterate the pixel with varying grey scale values
for (int y = 0; y < 15; y++) {
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
img[i][j] = color;
}
}
color = color + 15;
for (int i = 0; i < 256; i++) {
img[0][i] = 0;
img[i][0] = 0;
img[255][i] = 0;
img[i][255] = 0;
}
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
binaryFile.write((char*)&img[i][j], sizeof(img[i][j]));
}
}
}
// end raw file editing
binaryFile.close();
if (!binaryFile.good()) {
cout << "Error occurred at writing time!" << endl;
return 1;
}
}
So each row of pixels (from left to right) spans 4 different colored squares (4 columns using x), and each square is 256 pixels wide:
for (int x = 0; x < 4; x++) {
for (int j = 0; j < 256; j++) {
// write one pixel here
}
}
Each column of pixels (from top to bottom) also spans 4 different colored squares (4 rows using y), and each square is 256 pixels high:
for (int y = 0; y < 4; y++) {
for (int i = 0; i < 256; i++) {
// inner loop here
}
}
Then all you have to do is to determine the color of each square. The color should advance 1 "increment" of 17 (max color / number of increments = 255 / 15) for each row. And each row should advance the color 4 "increments" of 17.
Now i hear you say, 17? That can't be right. Just hold on a bit longer.
For each column x, increment by 1. And for each row y, increment by 4. That comes down to: x + ( y * 4 ). Apply the increment 17 like we said before, and you get: ( x + ( y * 4 ) ) * 17. Since the * takes precedence over +, the internal brackets ( ) are not needed, leaving just: (x+y*4)*17.
That will make the colors for each square look like this:
Col 0
Col 1
Col 2
Col 3
Row 0
0
17
34
51
Row 1
68
85
102
119
Row 2
136
153
170
187
Row 3
204
221
238
255
See? Nicely spaced colors, starting on 0 and ending on 255.
Putting it all together:
for (int y = 0; y < 4; y++) {
for (int i = 0; i < 256; i++) {
for (int x = 0; x < 4; x++) {
char color = (x+y*4)*17;
for (int j = 0; j < 256; j++) {
binaryFile.put(color);
}
}
}
}
Pixel data is written in order of rows. So writing blocks of 256x256 will not do the job. (You can consider this by thinking img[256][256] same as img[256*256]). To make this right, you must write a first row of first 4 blocks, then a second row of first 4 blocks, etc... (Block here means 256x256 section).
I think this code should do:
for (int row = 0; row < 1024; ++row) {
for (int col = 0; col < 1024; ++col) {
// the part ((row / 256) * 4 + (col / 256)) will go from 0 to 15
unsigned char color = ((row / 256) * 4 + (col / 256)) * 16;
if (row % 256 == 0 || col % 256 == 0) {
// This will not draw last border
color = 0;
}
// If you need last border uncomment below, but will reduce last block size by one
/*
if (row == 1024 - 1 || col == 1024 - 1) {
color = 0;
}
*/
binaryFile.write((char*) &color, sizeof(color));
}
}
Good day,
I am looking for a nested for loop to traverse the image of size 512x512 as 64x64 per iteration. My goal is to determine the element of each sub-region, such as performing number of edge count.
In this following code, I have tried to iterate per 64 row and 64 col (expect 8 times each to hit 512). Within the nested for loop, I have placed vec3b as a test run and I aware that the entire cycle of my code is repeating an identical pattern rather than traverse entire image.
int main()
{
char imgName[] = "data/near.jpg"; //input1.jpg, input2.jpg, near.jpg, far.jpg
Mat sourceImage = imread(imgName);
resize(sourceImage, sourceImage, Size(512, 512));
for (int t_row = 0; t_row < sourceImage.rows; t_row += 64)
{
for (int t_col = 0; t_col < sourceImage.cols; t_col += 64)
{
for (int row = 0; row < 64; row++)
{
for (int col = 0; col < 64; col++)
{
Vec3b bgrPixel = sourceImage.at<Vec3b>(row, col);
cout << bgrPixel << endl;
}
}
}
}
return 0;
}
If you actually want to have 64x64 sub-images per iteration, make use of OpenCV's Rect, like so:
const int w = 64;
const int h = 64;
for (int i = 0; i < int(sourceImage.size().width / w); i++)
{
for (int j = 0; j < int(sourceImage.size().height / h); j++)
{
cv::Mat smallImage = sourceImage(cv::Rect(i * w, j * h, w, h));
// Pass smallImage to any function...
}
}
You are iterating over
Vec3b bgrPixel = sourceImage.at<Vec3b>(row, col);
with 0 <= row < 64 and 0 <= col < 64. You are right that you iterate 64 times over the same region.
It should be
Vec3b bgrPixel = sourceImage.at<Vec3b>(t_row + row, t_col + col);
I am trying to implement Laplace sharpening using C++ , here's my code so far:
img = imread("cow.png", 0);
Mat convoSharp() {
//creating new image
Mat res = img.clone();
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = 0.0;
}
}
//variable declaration
int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
//int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
int height = img.rows;
int width = img.cols;
int filterHeight = 3;
int filterWidth = 3;
int newImageHeight = height - filterHeight + 1;
int newImageWidth = width - filterWidth + 1;
int i, j, h, w;
//convolution
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);
}
}
}
}
//img - laplace
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = img.at<uchar>(y, x) - res.at<uchar>(y, x);
}
}
return res;
}
I don't really know what went wrong, I also tried different filter (1,1,1),(1,-8,1),(1,1,1) and the result is also same (more or less). I don't think that I need to normalize the result because the result is in range of 0 - 255. Can anyone explain what really went wrong in my code?
Problem: uchar is too small to hold partial results of filerting operation.
You should create a temporary variable and add all the filtered positions to this variable then check if value of temp is in range <0,255> if not, you need to clamp the end result to fit <0,255>.
By executing below line
res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);
partial result may be greater than 255 (max value in uchar) or negative (in filter you have -4 or -8). temp has to be singed integer type to handle the case when partial result is negative value.
Fix:
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
int temp = res.at<uchar>(i,j); // added
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
temp += filter[h - i][w - j] * img.at<uchar>(h,w); // add to temp
}
}
// clamp temp to <0,255>
res.at<uchar>(i,j) = temp;
}
}
You should also clamp values to <0,255> range when you do the subtraction of images.
The problem is partially that you’re overflowing your uchar, as rafix07 suggested, but that is not the full problem.
The Laplace of an image contains negative values. It has to. And you can’t clamp those to 0, you need to preserve the negative values. Also, it can values up to 4*255 given your version of the filter. What this means is that you need to use a signed 16 bit type to store this output.
But there is a simpler and more efficient approach!
You are computing img - laplace(img). In terms of convolutions (*), this is 1 * img - laplace_kernel * img = (1 - laplace_kernel) * img. That is to say, you can combine both operations into a single convolution. The 1 kernel that doesn’t change the image is [(0,0,0),(0,1,0),(0,0,0)]. Subtract your Laplace kernel from that and you obtain [(0,-1,0),(-1,5,-1),(0,-1,0)].
So, simply compute the convolution with that kernel, and do it using int as intermediate type, which you then clamp to the uchar output range as shown by rafix07.
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.
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;