I have a project where we have to develop some image processing functions. One of the functions is shrinking an image.
this is the description of the function
void averageRegions(int blockWidth, int blockHeight)
INPUTS: Integers indicating the width and height of the blocks?to be averaged
OUTPUTS: NONE
When this function is called, you should create a new image that will consist of 1 pixel for every block of size
blockWidth by blockHeight pixels in the original image, with each pixel being the average color of the pixels in that
region in the original image.
Please note that it may be easier if you split this into 2 functions and call your helper function from within this one.
The second function could then just calculate the average value of a block of pixels given to it, and return that
to the original function to be used. However, this implementation is up to you! Complete it as you see fit.
I have completed the code of it however after closing the app I get this error
An unhandled exception of type 'System.AccessViolationException' occurred in MCS2514Pgm2.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
or this one
Heap Corruption Detected: after Normal block (#126) at 0x004cF6c0 CRT detected that the application wrote to memory after end of heap bugger.
This is the function code
void averageRegions(int blockWidth, int blockHeight)
{
//please add the code
int height = inImage.getHeight();
int width = inImage.getWidth();
pixel** myPixels = inImage.getPixels();
pixel* pixelptr;
int Rsum = 0, Gsum = 0, Bsum = 0;
int Ravg, Gavg, Bavg, pcount = 0, m, n;
outImage.createNewImage(width/blockWidth, height/blockHeight);
pixel** outPixels = outImage.getPixels();
//pixelptr = &myPixels[0][4];
for(int x = 0; x < height; x +=blockHeight)
{
for(int y = 0; y < width; y += blockWidth)
{
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
Rsum += myPixels[i][j].red;
Gsum += myPixels[i][j].green;
Bsum += myPixels[i][j].blue;
pcount++;
}
}
Ravg = Rsum/pcount;
Gavg = Gsum/pcount;
Bavg = Bsum/pcount;
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
myPixels[i][j].red = Ravg;
myPixels[i][j].green = Gavg;
myPixels[i][j].blue = Bavg;
m = x/blockHeight;
n = y/blockWidth;
outPixels[m][n].red = myPixels[i][j].red;
outPixels[m][n].green = myPixels[i][j].green;
outPixels[m][n].blue = myPixels[i][j].blue;
}
}
pcount=0;
Rsum = 0;
Gsum = 0;
Bsum = 0;
}
}
inImage = outImage;
}
this is the image.h
#ifndef IMAGE
#define IMAGE
#include <atlimage.h>
#include <string>
#include <cstdlib>
#include "globals.h"
#include "pixel.h"
using namespace std;
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
~image(); //the image destructor (deletes the dynamically created pixel array)
void createNewImage(int width, int height); //this function deletes any current image data and creates a new blank image
//with the specified width/height and allocates the needed number of pixels
//dynamically.
bool loadImage(string filename); //load an image from the specified file path. Return true if it works, false if it is not a valid image.
//Note that we only accept images of the RGB 8bit colorspace!
void saveImage(string filename); //Save an image to the specified path
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void viewImage(CImage* myImage); //This function is called by the windows GUI. It returns the image in format the GUI understands.
private:
void pixelsToCImage(CImage* myImage); //this function is called internally by the image class.
//it converts our pixel struct array to a standard BGR uchar array with word spacing.
//(Don't worry about what this does)
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
};
#endif
And this is Pixel.h
#ifndef PIXEL_H
#define PIXEL_H
class pixel
{
public:
unsigned char red; //the red component
unsigned char green; //the green component
unsigned char blue; //the blue component
};
#endif
Can any one tell me why I am getting this error
In addition:
the error is taking me to this line in dbgdel.cpp
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
This error occurs because you are accessing outside of memory allocated for an array. There are several places in your code where this can happen.
If height is not a multiple of blockHeight, or width is not a multiple of blockWidth, your i/j loops will access elements outside of the memory allocated for myPixels.
Another possibility is when writing to outPixels if blockHeight and blockWidth are not equal. Your computation of m and n may have the blockHeight and blockWidth swapped (you're dividing x by blockHeight).
In
for (int x = 0; x < height; x += blockHeight)
say height is 100 and blockHeight is 33
x == 0. 0 < 100, so the body is entered and iterates 0 -> 32
x == 33. 33 < 100, so the body is entered and iterates 33 -> 65
x == 66. 66 < 100, so the body is entered and iterates 66 -> 98
x == 99. 99 < 100, so the body is entered and iterates 99 -> 131
Sadly there is no 100 -> 131.
Related
I have this code:
QImage grayImage = image.convertToFormat(QImage::Format_Grayscale8);
int size = grayImage.width() * grayImage.height();
QRgb *data = new QRgb[size];
memmove(data, grayImage.constBits(), size * sizeof(QRgb));
QRgb *ptr = data;
QRgb *end = ptr + size;
for (; ptr < end; ++ptr) {
int gray = qGray(*ptr);
}
delete[] data;
It is based on this: https://stackoverflow.com/a/40740985/8257882
How can I set the color of a pixel using that pointer?
In addition, using qGray() and loading a "bigger" image seem to crash this.
This works:
int width = image.width();
int height = image.height();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
image.setPixel(x, y, qRgba(0, 0, 0, 255));
}
}
But it is slow when compared to explicitly manipulating the image data.
Edit
Ok, I have this code now:
for (int y = 0; y < height; ++y) {
uchar *line = grayImage.scanLine(y);
for (int x = 0; x < width; ++x) {
int gray = qGray(line[x]);
*(line + x) = uchar(gray);
qInfo() << gray;
}
}
And it seems to work. However, when I use an image that has only black and white colors and print the gray value, black color gives me 0 and white gives 39. How can I get the gray value in a range of 0-255?
First of all you are copying too much data in this line:
memmove(data, grayImage.constBits(), size * sizeof(QRgb));
The size ob Qrgb is 4 bytes, but according to the documentation, the size of a Format_Grayscale8 pixel is only 8 bits or 1 byte. If you remove sizeof(QRgb) you should be copying the correct amount of bytes, assuming all the lines in the bitmap are consecutive (which, according to the documentation, they are not -- they are aligned to at minimum 32-bits, so you would have to account for that in size). The array data should not be of type Qrgb[size] but ucahr[size]. You can then modify data as you like. Finally, you will probably have to create a new QImage with one of the constructors that accept image bits as uchar and assign the new image to the old image:
auto newImage = QImage( data, image.width(), image.height(), QImage::Format_Grayscale8, ...);
grayImage = std::move( newImage );
But instead of copying image data, you could probably just modify grayImage directly by accessing its data through bits(), or even better, through scanLine(), maybe something like this:
int line, column;
auto pLine = grayImage.scanLine(line);
*(pLine + column) = uchar(grayValue);
EDIT:
According to scanLine documentation, the image is at least 32-bit aligned. So if your 8-bit grayScale image is 3 pixels wide, a new scan line will start every 4 bytes. If you have a 3x3 image, the total size of the memory required to hold the image pixels will be 12. The following code shows the required memory size:
int main() {
auto image = QImage(3, 3, QImage::Format_Grayscale8);
std::cout << image.bytesPerLine() * image.height() << "\n";
return 0;
}
The fill method (setting all gray values to 0xC0) could be implemented like this:
auto image = QImage(3, 3, QImage::Format_Grayscale8);
uchar gray = 0xc0;
for ( int i = 0; i < image.height(); ++i ) {
auto pLine = image.scanLine( i );
for ( int j = 0; j < image.width(); ++j )
*pLine++ = gray;
}
Here is a code that decodes a WebM frame and put them in a buffer
image->planes[p] = pointer to the top left pixel
image->linesize[p] = strides betwen rows
framesArray = vector of unsigned char*
while ( videoDec->getImage(*image) == VPXDecoder::NO_ERROR)
{
const int w = image->getWidth(p);
const int h = image->getHeight(p);
int offset = 0;
for (int y = 0; y < h; y++)
{
// fwrite(image->planes[p] + offset, 1, w, pFile);
for(int i=0;i<w;i++){
framesArray.at(count)[i+(w*y)] = *(image->planes[p]+offset+ i) ;
}
offset += image->linesize[p];
}
}
.............................
How can I write intro buffer line by line not pixel by pixel or optimize the writing of frame intro buffer?
if the source image and destination buffer share the same Width, Height and bit per pixel, you can use std::copy to copy the whole image into it.
std::copy(image->planes[p] + offset, image->planes[p] + (image->getHeight(p) * image->linesize[p], framesArray.begin()) ;
if it is same bit per pixel but different width and height, you can use std::copy by line.
I am working on a project for my computer science class where we create a photomosaic of a source image. We have been given a base image class. Along with the standard constructors, this class contains getter functions to return the private pixel array data and image height and width. We were told to create a derived class for all of the filler images, which need to be stored in a linked list. I've got the majority of the program worked out, but I don't know how to replace blocks of the source image with the pixel data from a filler image.
#include "stdafx.h" //needed for the Windows display
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
using namespace std;
#include "globals.h" //some global variables are included here
#include "pixel.h" //includes the pixel class for storing individual pixels
#include "image.h" //includes the image class we will be using.
#include "fillerImage.h" //includes the fillerImage
#include "fillNode.h"
#include <sstream>
image* mosaic = displayed; //displayed is the current image in the gui, mosaic is the copy that will be the photomosaic
pixel** mospix = mosaic->getPixels();
pixel** headpix = head->data->pix; //I created a public member pixel** in the filler image class with the hope that I could use it to access the private pixel data of the base image class.
int mosaicWidth = displayed->getWidth() / blockWidth * FILLER_IMAGE_WIDTH;
int mosaicHeight = displayed->getHeight() / blockHeight * FILLER_IMAGE_HEIGHT;
//mosaic->createNewImage(mosaicWidth, mosaicHeight);
for (int i = 0; i < mosaicHeight; i = i + blockHeight)
{
for (int j = 0; j < mosaicWidth; j = j + blockWidth)
{
for (int blockrow = 0; blockrow < blockHeight; blockrow++)
{
for (int blockcol = 0; blockcol < blockWidth; blockcol++)
{
mospix = headpix;
}
}
}
displayed = mosaic;
}
displayed = mosaic;
I keep running into the problem of attempting to write to protected data; how can I modify the pixel data of mosaic? I'm not allowed to edit the base image class, just the filler image class. I apologize if my post is poorly formatted, this is my first time asking for help. Thanks in advance!
EDIT: Here is the image class header. I'm not allowed to modify this in any way, and it does not contain a setter for the pixel data.
#include "globals.h"
#include "pixel.h"
using namespace std;
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
~image(); //the image destructor (deletes the dynamically created pixel array)
void createNewImage(int width, int height); //this function deletes any current image data and creates a new blank image
//with the specified width/height and allocates the needed number of pixels
//dynamically.
bool loadImage(string filename); //load an image from the specified file path. Return true if it works, false if it is not a valid image.
//Note that we only accept images of the RGB 8bit colorspace!
void saveImage(string filename); //Save an image to the specified path
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void viewImage(CImage* myImage); //This function is called by the windows GUI. It returns the image in format the GUI understands.
private:
void pixelsToCImage(CImage* myImage); //this function is called internally by the image class.
//it converts our pixel object array to a standard BGR uchar array with word spacing.
//(Don't worry about what this does)
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
};
#endif
The only way to access to the pixels is via getPixel():
You can definitively read from it.
As this member function doesn't return a const pointer, and in absence of documentation, I assume that you can write on it as well.
With the following statement, you get access to the pixel array of mosaic.
pixel** mospix = mosaic->getPixels();
From that moment onwards, you can read/write any pixel directly by using mospix[i][j], as long as 0 <= i && i < mosaic->getHeight() && 0<=j && j<mosaic->getWidth().
There is however a serious problem in your code. In the nested loops, your inner statement is:
mospix = headpix;
This doesn't copy the current pixel as you seem to expect. It replaces the pointer that you had correctly initialized, with a copy of the pointer headpix. From then onwards, if you would access to a mospix array element, you would in reality let the picture inside mosaic unchanged, but you would access pixels in head->data !
I don't know exactly how you want to create the mosaic, but I think that there is a mismatch in the way you loop and could imagine that you wanted to say woemething like:
for (int i = 0; i < mosaic->getHeight(); i = i + blockHeight)
{
for (int blockrow = 0; blockrow < blockHeight; blockrow++)
{
for (int j = 0; j < mosaic->getWidth(); j = j + blockWidth)
{
for (int blockcol = 0; blockcol < blockWidth; blockcol++)
{
mospix[i+blockrow][j+blockcol] = headpix[blockrow][blockcol];
}
}
}
}
displayed = mosaic; // Not sure it's needed: both are pointers pointing to the same object
I'm having trouble rotating an image 90 degrees, the images are 768 x 768 pixels. The code I have shown here is able to create a new image, but the function I've written isn't manipulating it at all. My image class and function that's in the driver to rotate it is below. I have to rotate all the pictures 90 degrees clockwise and counterclockwise; I think my issue is trying to get the pointers to correctly switch the pixels around.
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
image(image &other); //copy constructor
~image(); //the image destructor (deletes the dynamically created pixel array)
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void createNewImage(int width, int height);
private:
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
void pixelsToCImage(CImage* myImage);
};
void RotateClockWise(image *imageIn)
{
image rotateImg;
image *ptr = (image*) &rotateImg;
*ptr = *imageIn;
int height = rotateImg.getHeight();
int width = rotateImg.getWidth();
pixel** rotatePix = rotateImg.getPixels();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rotatePix[i][j] = rotatePix[j][i];
*(ptr + j * height + (height - i - 1)) = *(ptr + i * width + j);
}
}
}
First your code is very c style. This is cool, I love this kind of coding, but you can make your life easier with references.
Solution for your code:
You never set point to imageIn, just the copy the value from image in to rotateImg:
image rotateImg;
image *ptr = (image*) &rotateImg;
*ptr = *imageIn;
This means you just modify the local variable rotateImg and not the object which is given by the pointer.
And here just a plain NO:
ptr points on an image. Each +j means "go to the next image" or more precissly: ptr = ptr + sizeof(image); which should be around 12 bytes + vtable. Dont do this. You You can just do this when you loop over an 1 dimensional pixel array.
*(ptr + j * height + (height - i - 1)) = *(ptr + i * width + j); //BAD
Here is some C style code which solves the problem. I did not know you could give a 2 dimensional array via a double pointer **ptr (indirect pointers).
void RotateClockWise(image* imageIn)
{
image rotateImg;
rotateImg = *imageIn;
image *ptr = imageIn;
int height = rotateImg.getHeight();
int width = imageIn->getWidth();
pixel** normalPix = rotateImg.getPixels();
pixel** rotatePix = imageIn->getPixels();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rotatePix[i][j] = normalPix[(height-1)-j][(width-1)-i];
}
}
}
I am to lazy to code it in C++ Style, but have a look at the Reference
void RotateClockWise(image& imageIn)
You have imageIn argument that probably points to image you want to rotate. However, you create rotateImg object, get pointer to this object (ptr) and duplicate imageIn to this ptr. So, now you manipulate image copy instead of image itself, that is why object pointed by imageIn never changes its value.
I am working on the implementation of functions for an already written image processing program. I am given explanations of functions, but not sure how they are designating pixels of the image.
In this case, I need to flip the image horizontally, i.e., rotates 180 degrees around the vertical axis
Is this what makes the "image" i am to flip?
void Image::createImage(int width_x, int height_y)
{
width = width_x;
height = height_y;
if (pixelData!=NULL)
freePixelData();
if (width <= 0 || height <= 0) {
return;
}
pixelData = new Color* [width]; // array of Pixel*
for (int x = 0; x < width; x++) {
pixelData[x] = new Color [height]; // this is 2nd dimension of pixelData
}
}
I do not know if all the functions I have written are correct.
Also, the Image class calls on a Color class
So to re-ask: what am I "flipping" here?
Prototype for function is:
void flipLeftRight();
As there is no input into the function, and I am told it modifies pixelData, how do I flip left to right?
A quick in place flip. Untested, but the idea is there.
void flipHorizontal(u8 *image, u32 width, u32 height)
{
for(int i=0; i < height; i++)
{
for(int j=0; j < width/2; j++)
{
int sourceIndex = i * width + j;
int destIndex = (i+1) * width - j - 1;
image[sourceIndex] ^= image[destIndex];
image[destIndex] ^= image[sourceIndex];
image[sourceIndex] ^= image[destIndex];
}
}
}
well, the simplest approach would be to read it 1 row at a time into a temporary buffer the same size as 1 row.
Then you could use something like std::reverse on the temporary buffer and write it back.
You could also do it in place, but this is the simplest approach.
EDIT: what i;ve described is a mirror, not a flip, to mirror you also need to reverse the order of the rows. Nothing too bad, to do that I would create a buffer the same size as the image, copy the image and then write it back with the coordinates adjusted. Something like y = height - x and x = width - x.