Face detector program in C via arrays - c

So I need to make a "face detector" program in C. Basically I need to input the number of "face detections", resolution height and width (max 120), and the coordinates of the "face". Then the input is three h*w arrays which serve as RGB values.
The output of the program should be the same RGB values from the input, but with a green rectangle connecting the coordinates (thus highlighting the face on the picture), and the alpha values in the rectangle being 255 (the rest being alpha=127).
The issue I have is that the outputs are completely wrong. The first test case, which is a 5x5 black square with false coordinates, works fine. But the other test cases are actual pictures with 100x80 resolution. In those cases instead of a green rectangle, its random green lines and dots around the picture. The alpha value is simmilarly wrong, where its randomly 127 and randomly 255. I've tried rewriting my code several times, but the result is the same every time, just random values for alpha and G.
#include <stdio.h>
#define MAX 120
int main() {
FILE* fin = fopen("input.txt", "r");
FILE* fout = fopen("output.txt", "w");
int R[MAX][MAX], G[MAX][MAX], B[MAX][MAX], x1[MAX], y1[MAX], x2[MAX],
y2[MAX], A[MAX][MAX];
int h, w, n, i, j, k;
fscanf(fin, "%d %d %d", &n, &h, &w);
for (i = 0; i < n; i++) {
fscanf(fin, "%d %d %d %d", &x1[i], &y1[i], &x2[i], &y2[i]);
}
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
fscanf(fin, "%d ", &R[i][j]);
}
}
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
fscanf(fin, "%d ", &G[i][j]);
}
}
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
fscanf(fin, "%d ", &B[i][j]);
}
}
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
A[i][j] = 127;
}
}
for (k = 0; k < n; k++) {
for (i = x1[k]; i <= x2[k]; ++i) {
G[i][y1[k]] = 255;
G[i][y2[k]] = 255;
A[i][y1[k]] = 255;
A[i][y2[k]] = 255;
R[i][y1[k]] = 0;
R[i][y2[k]] = 0;
B[i][y1[k]] = 0;
B[i][y2[k]] = 0;
}
for (j = y1[k]; j <= y2[k]; ++j) {
G[x1[k]][j] = 255;
G[x2[k]][j] = 255;
A[x1[k]][j] = 255;
A[x2[k]][j] = 255;
R[x1[k]][j] = 0;
R[x2[k]][j] = 0;
B[x1[k]][j] = 0;
B[x2[k]][j] = 0;
}
}
for (k = 0; k < n; k++) {
for (i = x1[k] + 1; i <= x2[k] - 1; i++) {
for (j = y1[k] + 1; j <= y2[k] - 1; j++) {
A[i][j] = 255;
}
}
}
fprintf(fout, "/image %d %d RGBA\n", h, w);
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
fprintf(fout, "%d %d %d %d ", R[i][j], G[i][j], B[i][j], A[i][j]);
}
}
return 0;
}

I don't see anything wrong with the logic you have so I would step through your solution with testcases like yano suggested to see if you are having issues reading things in.
You do make the mistake of not setting the R and B values to 0 when you set the G value to 255 for the rectangle.
Next I would do two things: sanitize your inputs and simplify your loops.
For sanitizing your inputs just make sure that your with, height, and number of faces are less than your max. The coordinates you receive for each face rectangle should all be less than w and h, but greater than 0. Also double check that your face rectangles are always in the format of: [bottom-left x val, bottom-left y val, top-right x val, top-right y val] like you assume when you do all of these calculations. If there were an input problem here, that would be my guess at the most likely to cause hidden issues.
You can simplify your loops to avoid touching anything outside of your rectangles when coloring the Alpha and Green.
For the Green values, just loop over the sides. Loop through all of the faces (n) like you are doing, but just do:
for (i = x1[n]; i <= x2[n]; ++i) { G[i][y1[n]] = 255; G[i][y2[n]] = 255; // Also set A to 255 as well as R and B to 0 here }
for (j = y1[n]; j <= y2[n]; ++j) { G[x1[n]][j] = 255; G[x2[n]][j] = 255; // Also set A to 255 as well as R and B to 0 here }
And then cover the Alpha values inside the rectangle by looping from x1[n] + 1 to x2[n] - 1 and y1[n] + 1 to y2[n] - 1. This will not only make your program quicker, but should stop any erroneous green or alpha values to show up anywhere outside of your given points.
After fixing those things it should be much easier to debug and see where errors are when you get unexpected behavior.
Edit: I missed a case for input sanitation.

Related

pset4 blur Segmentation fault

I'm stuck on my code for too much time now and needing some help. I'm working on CS50 pset4 blur filter and I keep getting either a "Segmentation fault" or "Floating point exception" depending if try to change my " neighbour variables" on float instead of int. Can someone have any idea what I'm doing wrong with that ?
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// Copy image to "copy"
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
// Loop through all the neighbour's pixel and calculate the average RGB in each
int RedNeighbour = 0; int BlueNeighbour = 0; int GreenNeighbour = 0; int neighbourSum = 0;
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
for(int k = i - 1; k < i + 1; k++)
{
for(int l = j - 1 ; l < j + 1; l++)
{
if(k >= 0 && k < height && l >= 0 && l < width)
{
RedNeighbour += copy[l][k].rgbtRed;
BlueNeighbour += copy[l][k].rgbtBlue;
GreenNeighbour += copy[l][k].rgbtGreen;
neighbourSum++;
}
else
{
continue;
}
}
}
// Divide each color by the sum of the neighbouring pixels and copy the pixe into original image
image[i][j].rgbtRed = round(fmin(255, RedNeighbour/neighbourSum));
image[i][j].rgbtBlue = round(fmin(255, BlueNeighbour/neighbourSum));
image[i][j].rgbtGreen = round(fmin(255, GreenNeighbour/neighbourSum));
}
}
return;
}
Thanks !
I'd recommend just using a debugger (gdb, or your IDE's if you're using one) for that kind of thing.
That said, I'm noticing that on the following lines, you are potentially accessing out of bound indices in your copy array:
RedNeighbour += copy[l][k].rgbtRed;
BlueNeighbour += copy[l][k].rgbtBlue;
GreenNeighbour += copy[l][k].rgbtGreen;
In your code, l is constrained by your width, while k is constrained by your height. However, the definition of the copy array is RGBTRIPLE copy[height][width];, which means that you should probably be accessing your copy array with copy[k][l] rather than copy[l][k].

Print repeating diamond shapes with custom rows, columns and length

I am new to C, and I am trying to print diamond shapes according to the rows(2~10), columns(2~10) and the length(3, 5, 7, 9) of the diamond input from the user.
Using the code below I can print diamond and number of diamonds correctly, but I just can't get the correct distance between them.
void printDiamondWith(int diamondlength, int numberOfDiamonds) {
int i, j, k;
int star, space;
star = 1;
space = diamondlength;
for (i = 1; i < diamondlength * 2 - 1; i++) {
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space; j++) {
printf(" "); // Print the distance for the previous star
}
for (j = 1; j < star * 2; j++) {
printf("*");
}
for (j = 0; j < space; j++) {
printf(" "); // Print the distance for the next star
}
}
printf("\n");
// Check if length is equal 3, else length -1 to get the correct rows of second half of the diamond
if (diamondlength == 3) {
// Loops until the first half of the diamond is finished, then reverse the process to print the second half
if(i < (diamondlength - diamondlength / 3)) {
space--;
star++;
} else {
space++;
star--;
}
} else if (diamondlength >= 3) {
if (i < (diamondlength - 1 - diamondlength / 3)) {
space--;
star++;
} else {
space++;
star--;
}
}
}
}
Actual running result:
Expected result:
Your formulas for calculating the space is off. It works for me when I change this
space = diamondlength;
to this
space = diamondlength/2+1;
And this
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space; j++) {
to this:
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space-1; j++) {
In such situations I recommend hardcoding the variable for different parameters and write down what the variable has to be for what parameter so you can try to find a function that maps the parameter to the value. For instance I saw that as diamondlength increased, the space error also increased, so the relation between parameter and variable can't be one to one.

Is there any way to speed up printing arrays?

So I have made this program where you can give in the parameters of a circle or a line and it will display said object by drawing an array on the display.
It works by "projecting" a coordinate-system onto an array. (The program also asks you to give the resolution of the array, the number of columns and rows are the same.) Then for every cell of the array it checks if the circle/line intersects the cell. If it does, or it is within a given range, the cell will get a value of 1. If it is out of range, it will be 0. When all the cells have been given a value, the program displays the array. So in the end you will see a circle or line made of ones, the rest of the arrays will show up in zeroes.
The problem is that it takes a relatively long time (7 to 10s) to print the array, while the actual calculations take like no time.
My question is as said in the title, can the process of displaying the array be sped up somehow? Or am I doing something wrong? I am using Code::Blocks as my compiler.
I know that my code is probably very poorly optimized, but I've only started programming like a week ago. So please forgive me if the code is hard to understand.
Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
int main()
{
float x = 0, y = 0, ypos= 0 , xpos = 0, radius = 0, rsqrd = 0, rcheck = 0, thick = 0, grad = 0, offs = 0, lcheck = 0;
int matsize = 0, i, j, branch = 0;
char filled;
printf("\n0 - circle\n1 - line\nDo you want to draw a circle or a line? (0/1) ");
scanf("%d", &branch);
if(branch == 0)
{
printf("Value of radius: ");
scanf("%f", &radius);
printf("Position of circle on the x axis: ");
scanf("%f", &xpos);
printf("Position of circle on the y axis: ");
scanf("%f", &ypos);
printf("Is the circle filled? (y/n) ");
scanf(" %c", &filled);
if(filled == 'n')
{
printf("The thickness of circle: ");
scanf("%f", &thick);
}
if(filled == 'y' || filled == 'n')
{
printf("Resolution: ");
scanf("%d" , &matsize);
printf("\n");
}
rsqrd = radius*radius; //rsqrd is equal to radius squared.
x = -1*(matsize/2); //with this I make sure that the x and y values start from the top right corner of the matrix, so that each x, y value corresponds to the correct cell position (i, j)
y = matsize/2;
int mat[matsize][matsize];
if(filled == 'n')
{
for(i = 0; i < matsize; i++)
{
for(j = 0; j < matsize; j++)
{
rcheck = ((y - ypos)*(y - ypos)) + ((x - xpos)*(x - xpos)); // calculating the equation of the circle with the x and y values taking the offset into account
if(abs(rcheck-rsqrd) <= (thick*thick))
{
mat[i][j] = 1;
}
else
{
mat[i][j] = 0;
}
x = x+1; //stepping the values of x and y so they stay with the corresponding cell
}
x = -1*(matsize/2);
y = y-1;
}
}
if(filled =='y')
{
for(i = 0; i < matsize; i++)
{
for(j = 0; j < matsize; j++)
{
rcheck = ((y - ypos)*(y - ypos)) + ((x - xpos)*(x - xpos)); // calculating the equation of the circle with the x and y values taking the offset into account
if(rcheck <= rsqrd)
{
mat[i][j] = 1;
}
else
{
mat[i][j] = 0;
}
x = x+1; //stepping the values of x and y so they stay with the corresponding cell
}
x = -1*(matsize/2);
y = y-1;
}
}
if(filled == 'y' || filled == 'n')
{
for(i = 0; i < matsize; i++) // displaying the matrix
{ //
for(j = 0; j < matsize; j++) //
{ //
printf("%d ",mat[i][j]); //
} //
printf("\n"); //
} //
}
}
if(branch == 1)
{
printf("Value of gradient: ");
scanf("%f", &grad);
printf("Value of offset: ");
scanf("%f", &offs);
printf("Thickness of line: ");
scanf("%f", &thick);
printf("Resoultion: ");
scanf("%d", &matsize);
x = -1*(matsize/2); //with this I make sure that the x and y values start from the top right corner of the matrix, so that each x, y value corresponds to the correct cell position (i, j)
y = matsize/2;
int mat[matsize][matsize];
for(i = 0; i < matsize; i++)
{
for(j = 0; j < matsize; j++)
{
lcheck = y - (x * grad); // calculating the equation of the circle with the x and y values taking the offset into account
if(abs(lcheck-offs) <= thick)
{
mat[i][j] = 1;
}
else
{
mat[i][j] = 0;
}
x = x+1; //stepping the values of x and y so they stay with the corresponding cell
}
x = -1*(matsize/2);
y = y-1;
}
if(branch == 1)
{
for(i = 0; i < matsize; i++) // displaying the matrix
{ //
for(j = 0; j < matsize; j++)//
{ //
printf("%d ",mat[i][j]);//
} //
printf("\n"); //
} //
}
}
return 0;
}
As I stated in my comment maybe it has something to do with this stack overflow question and answer
After reading a bit, you could also try to buffer your stdout in order to make it faster.

Printing a single dimension array in user specified columns in C language

I am trying to display the elements of an array in the number of columns that the user specifies. They decide how large the array is and how many columns it will be displayed in. Right now, I am printing the elements of the array in columns but, I have extra rows and columns with numbers that are not in the array. Thus if I select array size and column number as 5 3, I would hope to see:
1 3 5
2 4
Instead, I get something like:
1 3 5
2 4 107863456
128976543 58764 896543221
5643217 90876543456 8976543
I am getting 3 columns with 4 rows. I do not know why this is happening. Here is the portion of my code that deals with creating columns, let me know if more code is needed (x is variable that holds array size, y holds number of columns):
void colDisplay(int *aPtr, int x, int y) {
int i, j;
srand(time(NULL));
for(i = 0; i < x; i++) {
aPtr[i] = rand()%5+1;
}
/*Trying to format display for number of columns used*/
printf("Unsorted columns\n");
for(i = 0; i < x; i++) {
for(j = 0; j < y; j++) {
//printf("%d = %d ", (i*y)+j, aPtr[(i*y)+j]);
printf("%d ", aPtr[(i*y)+j]);
}
printf("\n");
}
}
The inner loop is counting the columns correctly, but the outer loop is using x as a row count, instead of an item count. To fix the problem you can use a single loop that counts items, and outputs newlines at the correct times.
j = 0;
for ( i = 0; i < x; i++ )
{
printf("%d ", aPtr[i] );
j++;
if ( j == y || i == x-1 )
{
printf( "\n" );
j = 0;
}
}
I agree with the solution by #user3386109.
Also, the following change will help:
Original 'for' loop with j:
for(j = 0; j < y; j++)
Modified code:
for (j = 0; (j < y) && (i*y+j < x); j++)
Reason: index = i*y+j may exceed x if (x % y != 0) i.e. if x (array size) is not integral multiple of y (display column size).
Because of arrays index out of bound.
You should do the following:
for(i = 0; i >= 0; i++) {
boolean isContinue = true;
for(j = 0; j < y; j++) {
int index = i*y+j;
if(index==x){
isContinue = false;
break;
}
printf("%d ", aPtr[(i*y)+j]);
}
if(!isContinue){
break;
}
printf("\n");
}

Regarding spatial resolution conversion programming - bmp image

I want to ask something about simple spatial resolution manipulating just by using c language. I have done my programming below, it managed to be compiled but for some reasons the program stucked in the middle when I try to run it. Really hope you guys can help. I am extremely beginner on this.
#include<stdio.h>
#define width 640
#define height 581
int main(void)
{
FILE *fp;
unsignedchar header[54];
unsignedchar img_work[width][height][3];
char input_file[128],output_file[128];
int v, h, w, i, c, s, ave_w[width], ave_h[height], average_h, average_w;
/*------------Reading image------------*/
printf("Enter name of the file¥n---");
scanf("%s",input_file);
printf("The file that would be processed is %s.¥n", input_file);
fp=fopen(input_file,"rb");
fread(header,1,54,fp);
fread(img_work,1,width*height*3,fp);
fclose(fp);
/*------------Spatial Resolution Program------------*/
printf ("enter level of spatialization-- ");
scanf ("%d", &v);
for (i=0; i<v; i++) {
s = s + s;
}
for(c=0; c<3; c++){
for(h=0; h<height; h++){
for(w=0; w<width; w=w+s){
average_w = 0;
for (i=0; i<s; i++) {
ave_w = img_work[w+i][h][c] / s;
average_w = average_w + ave_w;
}
for (i=0; i<width; i=i+s) {
img_work[w+i][h][c] = average_w;
}
}
}
}
for(c=0; c<3; c++){
for(w=0; w<width; w++){
for(h=0; h<height; h=h+s){
average_h = 0;
for (i=0; i<s; i++) {
ave_h = img_work[w][h+i][c] / s;
average_h = average_h + ave_h;
}
for (i=0; i<height; i=i+s) {
img_work[w][h+i][c] = average_h;
}
}
}
}
/*------------Writing File------------*/
printf("Enter the name of the file that would be saved.¥n---");
scanf("%s",output_file);
printf("Name of the file that would be saved is %s.¥n",output_file);
fp=fopen(output_file,"wb");
fwrite(header,1,54,fp);
fwrite(img_work,1,width*height*3,fp);
fclose(fp);
printf("End.¥n");
return 0;
}
I am really a beginner, so, sorry if this is lacking too much.
There are several issues with your code:
s is uninitialised. Hence, when you access its value in the assignment s = s + s, the result is undefined. s may even be negative. Initialise it: s = 1;
You've got the representation of your image wrong. You read the pixel data verbatim from the file. The BMP format is row major, so your pixel data should be img_work[height][width][3] and all accesses should have their first and second dimensions swapped.
The BMP format also requires padding at the end of each row. Your fixed-size width of 640 doesn't require it, but it's worth keeping in mind when you want to make your implementation more general.
You don't really need the auxiliary variables ave_w and ave_h. Most importantly, you don't need them to be arrays.
Your height isn't evenly divisible by s. That means that in the last pass through the loop, h + i will go out of bounds. (The same applies to the width, but the value 640 is safe up to at least a level of 7.) You could calculate an "actual s" that would be adjusted for the top and right sides.
When you calculate the average, it is better to sum the values first and then divide by s once. You are dealing with integers and integer division truncates. For example 3/4 is zero. Consequently, (3/4 + 3/4 + 3/4 + 3+4) is also zero, but (3 + 3 + 3 + 3) / 4 is 3. You can notice the effect for larger levels of reduction, where a predominantly white imagfe becomes darker if you divide on summation.
Here's a program based on yours, that puts the points raised above into practice:
#include <stdio.h>
#define width 640
#define height 581
int main(void)
{
FILE *fp;
unsigned char header[54];
unsigned char img_work[height][width][3];
char input_file[128];
char output_file[128];
int v, h, w, i, c, s;
/*------------Reading image------------*/
printf("Enter name of the file\n---");
scanf("%s",input_file);
printf("The file that would be processed is %s.\n", input_file);
fp=fopen(input_file,"rb");
fread(header,1,54,fp);
fread(img_work,1,width*height*3,fp);
fclose(fp);
/*------------Spatial Resolution Program------------*/
printf("enter level of spatialization-- ");
scanf("%d", &v);
s = 1;
for (i = 0; i < v; i++) {
s = s + s;
}
for (c = 0; c < 3; c++) {
for (h = 0; h < height; h++) {
for (w = 0; w < width; w = w + s) {
int average_w = 0;
int ss = s;
if (w + ss > width) ss = width % s;
for (i = 0; i < ss; i++) {
average_w = average_w + img_work[h][w + i][c];
}
for (i = 0; i < ss; i++) {
img_work[h][w + i][c] = average_w / ss;
}
}
}
}
for (c = 0; c < 3; c++) {
for (w = 0; w < width; w++) {
for (h = 0; h < height; h = h + s) {
int average_h = 0;
int ss = s;
if (h + ss > height) ss = height % s;
for (i = 0; i < ss; i++) {
average_h = average_h + img_work[h + i][w][c];
}
for (i = 0; i < ss; i++) {
img_work[h + i][w][c] = average_h / ss;
}
}
}
}
/*------------Writing File------------*/
printf("Enter the name of the file that would be saved.\n---");
scanf("%s",output_file);
printf("Name of the file that would be saved is %s.\n",output_file);
fp=fopen(output_file,"wb");
fwrite(header,1,54,fp);
fwrite(img_work,1,width*height*3,fp);
fclose(fp);
printf("End.\n");
return 0;
}
That's still a quick-and-dirty program with fixed image sizes. It doesn't enforce that the actual size of the image, which can be read from the header, and the fixed sizes match or that the colour depth is the same or that you even get enough pixel data, for which you should check the return value of fread.

Resources