Diagonal line in PNM P6 not drawing correctly - c

I am currently writing a program for an assignment that requires a single black line to be drawn perfectly solid diagonal (so that all x=y) from the upper-left corner of a standard PNM P6 file. I have had no issues with file I/O.
However, I cannot get the diagonal line to display properly. Instead of the single, solid, white line I need from the corner, I get dotted lines wrapping over the image as shown in this picture.
Does anyone have any idea as to what is going wrong?
My function is as follows:
Image *
DiagonalWhite(Image *img)
{
int i, j;
for (i = 0; i < img->x; i++)
{
for (j=0; j < img->y; j++)
{
if (i==j)
{
img->data[i*img->y+j].red=255;
img->data[i*img->y+j].green=255;
img->data[i*img->y+j].blue=255;
}
}
}
return img;
}

You don't give any definition for Image *img, so actually this question cannot be answered with confidence; however, I assume you are doing the same class as yesterday's Issues writing PNM P6.
You are multiplying in the wrong direction. img->y holds the height of the image. However, since you need the span, you should be using img->x -- the width -- to go down by i pixels (followed by adding j pixels to go right).
img->data[i*img->x+j].red=255; /* x, not y */
Note: Better names for these properties would have been width and height.
Note: It's easier and quicker to loop only once over the minimum of width and height, and set pixel[i,j] immediately, rather than testing which one 'has' the same x and y position.

Related

Pixel manipulation with SDL surface?

I'm trying to play around with image manipulation in C and I want to be able to read and write pixels on an SDL Surface. (I'm loading a bmp to a surface to get the pixel data) I'm having some trouble figuring out how to properly use the following functions.
SDL_CreateRGBSurfaceFrom();
SDL_GetRGB();
SDL_MapRGB();
I have only found examples of these in c++ and I'm having a hard time implementing it in C because I don't fully understand how they work.
so my questions are:
how do you properly retrieve pixel data using GetRGB? + How is the pixel addressed with x, y cordinates?
What kind of array would I use to store the pixel data?
How do you use SDL_CreateRGBSurfaceFrom() to draw the new pixel data back to a surface?
Also I want to access the pixels individually in a nested for loop for y and x like so.
for(int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
// get/put the pixel data
}
}
First have a look at SDL_Surface.
The parts you're interested in:
SDL_PixelFormat*format
int w, h
int pitch
void *pixels
What else you should know:
On position x, y (which must be greater or equal to 0 and less than w, h) the surface contains a pixel.
The pixel is described by the format field, which tells us, how the pixel is organized in memory.
The Remarks section of SDL_PixelFormat gives more information on the used datatype.
The pitch field is basically the width of the surface multiplied by the size of the pixel (BytesPerPixel).
With the function SDL_GetRGB, one can easily convert a pixel of any format to a RGB(A) triple/quadruple.
SDL_MapRGB is the reverse of SDL_GetRGB, where one can specify a pixel as RGB(A) triple/quadruple to map it to the closest color specified by the format parameter.
The SDL wiki provides many examples of the specific functions, i think you will find the proper examples to solve your problem.

(PSET4 Filter "grayscale") What exactly is check50 saying is wrong about my code?

I'm tasked with writing a program that applies a gray scale filter to a given image. This is done by looping over each pixel and averaging the rgb values. When I check my code, I receive an error which seems to say "ERROR: expected X, received X". Any clarifications of the error message or comments about possible bugs are appreciated.
My code loops over each pixel in each row of an array of pixels which are described as RGBTRIPLES, structs comprised of 3 uint8_t's. In the case of a non-whole-number average the program rounds up to the nearest whole number. My answer is the code included below.
My problem comes when I run check50 cs50/problems/2021/x/filter/more, a program which tests students' programs against keys made by the course designers. The 7th test check's the program's accuracy in filtering a "complex" 3x3 image; I get the following result:
:( grayscale correctly filters more complex 3x3 image
expected "20 20 20\n50 5...", not "20 20 20\n50 5..."
I am confused as it seems that my output matches the expected. Could someone give me a hint as to what my problem is?
My code:
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
//Loop over pixels
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//Average out rgbs to get a corresponding greyscale value
BYTE average_activation = ceil(((float) image[y][x].rgbtBlue + image[y][x].rgbtRed + image[y][x].rgbtGreen) / 3);
RGBTRIPLE resultant_pixel = {average_activation, average_activation, average_activation};
//apply
image[y][x] = resultant_pixel;
}
}
return;
}
I think you are overcomplicating things you should use round instead of ceil using #include <math.h>. Also you shouldn't define the new pixel per each pixel in the image. Instead define a new image that is the same width and height as the old image and replace every pixel in this image. At the end substitute the new image with the old image.

Why are my circles displaying as black?

I'm trying to make a program that creates up to 24 circles in a neat lattice that start off as white, and then as conditions (such as the hammer reaching the bottom of the screen and resetting) are met, changing those circles in order from left to right - going down one row each time the x-axis circles reach the defined edge of their row.
I created an array that holds the 24 colours in its indexes, all set to white ( - the same as the background for invisible circles) at the beginning, but changing one by one with the conditions. However, when I run my code below, I get an unchanging lattice of all black circles from the very beginning without considering the hammer, and the upper-left circle of every seventh row having a little white dot in it (only one visible in the 6-row test run).
I have no clue what caused this, and having scanned the code numerous times, I can't see where black is coming in from at all. The hammerPos if statement is incomplete at this point, as I'm still trying to figure out what's going on.
Here's my code:
int hammerPos = 0; int hammerVel = 1; int hammerPending = 0;
int jump = 60;
int pointIntervX = 20;
int pointIntervY = 20;
int pointX = pointIntervX;
int pointY = pointIntervY;
int pointSize = 10;
color white = color(255,255,255);
color black = color(0,0,0);
color red = color(255,0,0);
color[] pointColour = new color[24];
//standalone method (at top outside of draw and setup)
void pointMaker(color colour, int pointX, int pointY){
fill(colour);
ellipse(pointX,pointY,pointSize,pointSize);
}
void setup(){
size(200,200);
background(255);
for(int i:pointColour){//setup pointColour array at BEGINNING of setup
pointColour[i] = white;
}
}
void draw(){
// draw hammer;
fill(0);
stroke(0);
strokeWeight(6);
line(128,hammerPos+10,148,hammerPos-12);
strokeWeight(4);
line(125,hammerPos+13,129,hammerPos+11);
strokeWeight(8);
line(115,hammerPos+5,130,hammerPos+20);
hammerPending = hammerPending + hammerVel;
if (hammerPending > jump){
hammerPos = hammerPos + hammerPending;
hammerPending = 0;
}
for(int i = 0;i<24;i++){//refreshes 24 circles in white(invisible) constantly in draw until a color is changed
pointMaker(pointColour[i], pointX, pointY);
pointX += pointIntervX;
if(pointX>pointIntervX*4){
pointX = pointIntervX;
if(pointY<pointIntervY*6){
pointY += pointIntervY;
}
}
}
if(hammerPos>height){
hammerPos = 0;
}
}
The for loop in draw() is executed in the context where strokeWeight(8) is still in force. You are seeing nothing but stroke. A simple fix would be to put the line strokeWeight(1); at the beginning of the definition of pointMaker.
When you do that, you see another bug. for(int i:pointColour) doesn't do what you think it does. You are iterating over the default elements (not the indices) of the array pointColour -- all of which are 0. Thus what you are doing in that loop is 24 times in a row setting the first element of that array to white, leaving the other 23 equal to 0, which is equal to black. Hence after fixing the strokeWeight bug you are left with a grid of 1 white and 23 black circles. You should either initialize the array when you create it or in setup() loop over the indices rather than the elements by using for(int i = 0; i < pointColour.length; i++) {
On Edit: To clarify what I meant by index vs. element: pointColour was declared as color[24]. Thus for(int i: pointColour) doesn't really make sense. Using that type of iteration it should be for(color i: pointColour). The only reason that what you wrote isn't a syntax error is that Processing's color data type seems to be an alias for a 32-bit int. The indices in pointColour are always the 24 integers 0,1,...,23. The elements of pointColour are whatever 24 colors that you happen to store in that array. In pointColour[2] = color(0,0,255) the index is 2 but the element is the color blue

Processing - Basic! Ellipse getting progressively smaller using loop

I'm just learning the basics of Processing and I'm stuck with loops. How do I make a line of ellipses (maybe 7?) get progressively smaller and still have them attached?
This is the code so far but it's not working!
size (400,400);
float y=200;
for(int x=20; x<100; x=x+20) {
for (int size=40; size<100; size=size-5) {
ellipse (x,y,size,size);
x=x+20;
}
}
Also, another question! Here is a grid of crosses in circles. Using a loop, how do I get a row of five, followed by a row of four underneath, then three etc.
int x=20;
int y=30;
size(100,100); //set size of canvas screen
for(int i=0; i<5 ; i++) {
for (int j=0; j<5; j++) {
x=x+10; //add 10 to value stored in variable x
ellipse(x,y,10,10);
line (x-5,y,x+5,y);
line (x,y-5,x,y+5);
}
x=20;
y=y+10;
}
The best thing you can do when you have questions like this is to get out a piece of graph paper and draw out some examples. What is the radius of the first circle? What is its X value? What is the radius of the second circle? What is its X value?
Keep drawing examples until you notice a pattern, and then you can use that pattern in your for loop.
Hint: I don't think you need a nested for loop (a for loop inside another for loop). I think you can do this with just a single for loop.

openGL 2D pixel rotation

I'm trying to rotate a 2D pixel matrix, but nothing actually happens.
my origin is a stored bitmap[w x h x 3].
why isn't the shown image being rotated?
Here's the display function:
void display()
{
uint32_t i = 0,j = 0,k = 0;
unsigned char pixels[WINDOW_WIDTH * WINDOW_HEIGHT * 3];
memset(pixels, 0, sizeof(pixels));
for(j = bitmap_h -1; j > 0; j--) {
for(i = 0; i < bitmap_w; i++) {
pixels[k++]=bitmap[j][i].r;
pixels[k++]=bitmap[j][i].g;
pixels[k++]=bitmap[j][i].b;
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(90,0,0,1);
glDrawPixels(g_img.descriptor.size_w, g_img.descriptor.size_h, GL_RGB, GL_UNSIGNED_BYTE, &pixels);
glutSwapBuffers();
}
First and foremost glDrawPixels should not be used. The problem you have is one of the reasons. The convoluted rules by which glDrawPixels operate are too vast to outline here, let's just say, that there's a so called "raster position" in your window, at which glDrawPixels will place the lower left corner of the image it draws. No transformation whatsoever will be applied to the image.
However when setting the raster position, that's when transformations get applied. And should, for whatever reason, the raster position lie outside the visible window nothing will get drawn at all.
Solution: Don't use glDrawPixels. Don't use glDrawPixels. DON'T USE glDrawPixels. I repeat DON'T USE glDrawPixels. It's best you completely forget that this function actually exists in legacy OpenGL.
Use a textured quad instead. That will also transform properly.
I did something similar. I'm creating a 3D space shooter game using OpenGL/C++. For one of my levels, I have a bunch of asteroids/rocks in the background each rotating and moving at a random speed.
I did this by taking the asteroid bitmap image and creating a texture. Then I applied the texture to a square (glBegin(GL_QUADS)). Each time I draw the square, I multiply each of the vertex coordinates (glVertex3f(x, y, z)) with a rotation matrix.
|cos0 -sin0|
|sin0 cos0 |
0 is the theta angle. I store this angle as part of my Asteroid class. each iteration I increment it by a value, depending on how fast I want the asteroid to spin. It works great.

Resources