Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm trying to rotate an image pixel by pixel by 90 degrees, It seems there is a math problem that I couldn't figure out...and array out of bounds exception
here is my attempt
const unsigned char *srcData = source.getData();
unsigned char *dstData = new unsigned char[width * height * bpp];
size_t srcPitch = source.getRowSpan();
size_t dstPitch = width * bpp;
for(int i=0; i<height; i++)
{
for(int j=0; j<width * bpp; j++)
{
rotatedData[(i * dstPitch) + j]= dstData[(height-i) * dstPitch + j];
}
}
First, let's build an image descriptor to keep track of the dimensions.
struct ImageDescriptor {
std::size_t width;
std::size_t height;
std::size_t channels;
std::size_t stride() const { return width * channels; }
std::size_t offset(std::size_t row, std::size_t col, std::size_t chan) {
assert(0 <= row && row < height);
assert(0 <= col && col < width);
assert(0 <= chan && chan < channels);
return row*stride() + col*channels + chan;
// or, depending on your coordinate system ...
// return (height - row - 1)*stride() + col*channels + chan;
}
std::size_t size() const { return height * stride(); }
};
Now we'll need two ImageDescriptors to keep track of the dimensions of our two images. Note that, unless the original image is square, the rotated image will have a different width and height (and thus stride). Specifically, the width of the rotated image will be the height of the source image (and vice versa).
const ImageDescriptor source(width, height, bpp);
ImageDescriptor target(height, width, bpp); // note width/height swap
A common way to do a transformation is to loop over the destination pixels and look up the source pixels.
unsigned char *rotated = new[target.size()];
for (std::size_t row = 0; row < target.height; ++row) {
for (std::size_t col = 0; col < target.width; ++col) {
for (std::size_t chan = 0; chan < target.channels; ++chan) {
rotated[target.offset(row, col, chan)] =
original[source.offset(col, row, chan)];
}
}
}
Once you get it right, you can work to eliminate unnecessary computation. The first opportunity is to just step our way through the destination image, since all that is in memory order. The second opportunity is, to hoist the source offset calculation out of the channel loop. Finally, if bpp is a constant, you can unroll the innermost loop.
unsigned char *p = rotated;
for (std::size_t row = 0; row < target.height; ++row) {
for (std::size_t col = 0; col < target.width; ++col) {
const std::size_t base = source.offset(col, row, 0);
for (std::size_t chan = 0; chan < target.channels; ++chan) {
*p++ = original[base + chan];
}
}
}
Try this one:
for (int j = 0; j<width * bpp; j++)
{
for (int i = 0 ; i<height; i++)
{
rotatedData[(height)*(dstPitch - j - 1) + i] = dstData[(i * dstPitch) + j];
}
}
and if dstData isn't squared:
//define rotatedData_height before.
rotatedData[(rotatedData_height)*(dstPitch - j - 1) + i] = dstData[(i * dstPitch) + j];
Related
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 have the following image, I would like to rotate and flip it so that it fits the full screen resolution.
I'm doing the following conversion, to rotate, but it doesn't work.
Here is the source image.
size_t bpp = Ogre::PixelUtil::getNumElemBytes(source.getFormat());
const unsigned char *srcData = source.getData();
unsigned char *dstData = new unsigned char[width * height * bpp];
size_t srcPitch = source.getRowSpan();
size_t dstPitch = width * bpp;
ImageDescriptor sourceImage(source.getWidth(), source.getHeight(), bpp);
ImageDescriptor rotatedTarget(source.getHeight(), source.getWidth(), bpp); // note width/height swap
unsigned char *rotated = new unsigned char[source.getHeight() * source.getWidth() * bpp];
for (std::size_t row = 0; row < rotatedTarget.mHeight; ++row) {
for (std::size_t col = 0; col < rotatedTarget.mWidth; ++col) {
for (std::size_t chan = 0; chan < rotatedTarget.mChannels; ++chan) {
rotated[rotatedTarget.offset(col, row, chan)] =
srcData[sourceImage.offset(row, col, chan)];
}
}
}
struct ImageDescriptor {
std::size_t mWidth;
std::size_t mHeight;
std::size_t mChannels;
ImageDescriptor(std::size_t width, std::size_t height, std::size_t channels)
{
mWidth = width;
mHeight = height;
mChannels = channels;
}
std::size_t stride() const { return mWidth * mChannels; }
const std::size_t offset(std::size_t row, std::size_t col, std::size_t chan) {
assert(0 <= row && row < mHeight);
assert(0 <= col && col < mWidth);
assert(0 <= chan && chan < mChannels);
// return row*stride() + col*mChannels + chan;
// or, depending on your coordinate system ...
return (mHeight - row - 1)*stride() + col*mChannels + chan;
}
std::size_t size() const { return mHeight * stride(); }
};
Here is the result image.
Answer Result.
Any ideas?
Simple enough, invert the rows, change
rotated[rotatedTarget.offset(col, row, chan)] =
srcData[sourceImage.offset(row, col, chan)];
to
rotated[rotatedTarget.offset(rotatedTarget.mWidth-col-1, row, chan)] =
srcData[sourceImage.offset(row, col, chan)];
Something like that anyway. I'm a bit confused about your code.
after trying to implement a Gaussian blur for an image i have ran into a problem where the output image looks like multiple blurred versions of the original image (input image)
I have too low of a reputation to post images so have no idea how to fully show you what is happening however, i can post a gyazo link to the image:
https://gyazo.com/38fbe1abd442a3167747760866584655 - Original,
https://gyazo.com/471693c49917d3d3e243ee4156f4fe12 - Output
Here is some code:
int kernel[3][3] = { 1, 2, 1,
2, 4, 2,
1, 2, 1 };
void guassian_blur2D(unsigned char * arr, unsigned char * result, int width, int height)
{
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
for (int k = 0; k < 3; k++)
{
result[3 * row * width + 3 * col + k] = accessPixel(arr, col, row, k, width, height);
}
}
}
}
int accessPixel(unsigned char * arr, int col, int row, int k, int width, int height)
{
int sum = 0;
int sumKernel = 0;
for (int j = -1; j <= 1; j++)
{
for (int i = -1; i <= 1; i++)
{
if ((row + j) >= 0 && (row + j) < height && (col + i) >= 0 && (col + i) < width)
{
int color = arr[(row + j) * 3 * width + (col + i) * 3 + k];
sum += color * kernel[i + 1][j + 1];
sumKernel += kernel[i + 1][j + 1];
}
}
}
return sum / sumKernel;
}
Image is saved:
guassian_blur2D(inputBuffer, outputBuffer, width, height);
//Save the processed image
outputImage.convertToType(FREE_IMAGE_TYPE::FIT_BITMAP);
outputImage.convertTo24Bits();
outputImage.save("appleBlur.png");
cout << "Blur Complete" << endl;
Any help would be great, if this also helps i am trying to store the image as a grey-scale so that no colour is saved.
Looks like the problem is not within your blurring code, and is related to saving or accessing image data.
I have used OpenCV to read/save images, and got expected result. Here's a snippet:
cv::Mat3b img = cv::imread("path_to_img.png");
cv::Mat3b out = img.clone();
guassian_blur2D(img.data, out.data, img.cols, img.rows);
cv::imshow("img", img);
cv::imshow("out", out);
cv::waitKey(0);
And here are input and output images:
The blur is not very noticeable (due to high image resolution and small kernel), but if you look carefully - it looks correct.
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'm trying to flip an image vertically, after retrieving the buffer from openGL. It seems to be outputting an incorrect image with the following code:
const int width = 100;
const int height = width;
const int components = 3;
unsigned char pixels[width * height * components];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
unsigned char flipPixels[width * height * components];
for (int i = 0; i < width; ++i) {
for (int j = 0; j < height; ++j) {
for (int k = 0; k < components; ++k) {
flipPixels[i + j * width + k] = pixels[(height) * (width) - ((j+1) * width) + i + k];
}
}
}
I know I can only iterate half the height and achieve the same, but I want to implement it by going through the complete height of the image. I can't seem to figure out what's wrong with the code. Any help would be appreciated.
I'm not sure how the image is stored but your indices i and k are given the same stride which is suspicious. Maybe you want i * components and j * width * components. After that, inverting vertically you should only have to change j to (height - j - 1).
flipPixels[(i + j * width) * components + k] = pixels[(i + (height - 1 - j) * width) * components + k];
I had the same issue, the pixels returned by OpenGL resulten in an upside down bitmap. so I flipped them like this: but the bitmap is still flipped left to right...
void Flip(GLubyte* pixels, int pixelbuffersize)
{
// basically rewrites from bottom up...
std::vector<GLubyte> flipped_pixels(pixels, pixels+pixelbuffersize);
auto count = flipped_pixels.size();
std::reverse(flipped_pixels.begin(), flipped_pixels.end());
GLubyte* buff = (reinterpret_cast<GLubyte*>(&flipped_pixels[0]));
const void * pnewdata = (const void *)buff;
memcpy(pixels, pnewdata, count);
}