CS50 Filter Blur - cs50

I don't know what I do wrong. Its work on images but when output calculate answer is wrong.
ERROR output calculate
:( blur correctly filters middle pixel
expected "127 140 149\n", not "145 160 169\n"
:( blur correctly filters pixel on edge
expected "80 95 105\n", not "90 106 116\n"
:) blur correctly filters pixel in corner
:( blur correctly filters 3x3 image
expected "70 85 95\n80 9...", not "70 85 95\n90 1..."
:( blur correctly filters 4x4 image
expected "70 85 95\n80 9...", not "70 85 95\n90 1..."
this is my code.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
double red = 0,green = 0,blue = 0;
int count = 0;
for (int m = 0; m < 3; m++)
{
int h = i+m-1;
for (int n = 0; n < 3; n++)
{
int w = j+n-1;
if(h > -1 && w > -1 && h < height && w < width)
{
red += image[h][w].rgbtRed;
green += image[h][w].rgbtGreen;
blue += image[h][w].rgbtBlue;
count++;
}
}
}
red = 1.00*red/count;
green = 1.00*green/count;
blue = 1.00*blue/count;
image[i][j].rgbtRed = round(red);
image[i][j].rgbtGreen = round(green);
image[i][j].rgbtBlue = round(blue);
}
}
return;
}
May someone explain to me? I dont know why.

Related

Why does my cs50 sepia filter not compute the right pixel values?

for some reason the math portion of my sepia code does not seem to work. I get errors when I run check50, and it shows all the pixel values as being too high. I triple check the values for the filter but all seems good.
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
float org_red = 0;
float org_green = 0;
float org_blue = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
org_red = image[i][j].rgbtRed;
org_green = image[i][j].rgbtBlue;
org_blue = image[i][j].rgbtGreen;
long sepiaRed = (.393 * org_red + .769 * org_green + .189 * org_blue);
long sepiaGreen = (.349 * org_red) + .686 * org_green + .168 * org_blue;
long sepiaBlue = (.272 * org_red + .534 * org_green + .131 * org_blue);
if (sepiaRed > 255)
{
sepiaRed = 255;
}
if (sepiaGreen > 255)
{
sepiaGreen = 255;
}
if (sepiaBlue > 255)
{
sepiaBlue = 255;
}
image[i][j].rgbtRed = round(sepiaRed);
image[i][j].rgbtGreen = round(sepiaGreen);
image[i][j].rgbtBlue = round(sepiaBlue);
}
}
return;
}
The error i get says
:( sepia correctly filters single pixel
expected "56 50 39\n", not "84 75 58\n"
:( sepia correctly filters simple 3x3 image
expected "100 89 69\n100...", not "100 88 69\n100..."
:( sepia correctly filters more complex 3x3 image
expected "25 22 17\n66 5...", not "30 27 21\n71 6..."
:( sepia correctly filters 4x4 image
expected "25 22 17\n66 5...", not "30 27 21\n71 6..."

CS50 Filter grayscale check50

The grayscale code seems to run fine with programs having whole number as average. But gives error with complex averages, where the result is different from expected code by just 1.
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
double avgcolor;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
avgcolor = (image[i][j].rgbtRed + image[i][j].rgbtBlue + image[i][j].rgbtGreen) / 3;
image[i][j].rgbtRed = image[i][j].rgbtBlue = image[i][j].rgbtGreen = round(avgcolor);
}
}
return;
}
Error Message
:( grayscale correctly filters single pixel without whole number average
Cause
expected "28 28 28\n", not "27 27 27\n"
Log
testing with pixel (27, 28, 28)
running ./testing 0 1...
checking for output "28 28 28\n"...
Expected Output:
28 28 28
Actual Output:
27 27 27
I get such errors in two other cases. It could be a minor issue with the round function. Ive gone through the code several times but still cant find the cause of error.
You are dividing two integers, so C will compute your average, which may not be a whole number, and then drop what comes after the decimal point. Because image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtRed will always be an integer, dividing this integer value by another integer, 3, will return yet another integer, regardless of any decimal point. In other words, if image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtRed/3 = 27.66 then avgcolor will equal 27. A solution to this would be to divide the color values by 3.0, a float, instead. An integer divided by a float can return a float, but not an integer divided by an integer.
Try this code, where you do an integer by float division with 3.0:
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
double avgcolor;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
avgcolor = (image[i][j].rgbtRed + image[i][j].rgbtBlue + image[i][j].rgbtGreen) / 3.0;
image[i][j].rgbtRed = image[i][j].rgbtBlue = image[i][j].rgbtGreen = round(avgcolor);
}
}
return;
}

I want to track 2 colours, but only record the movement of those two colours and hide the video feed

For context: I am going to analyze the breathing movement of parents during kangaroo mother care and I wish to respect their privacy by not recording them, but only the movement of stickers I placed on their chest and stomach.
So far, I'm able to track 2 colours based on webcam input through the code below. However, I would like to record only the tracked colours instead of the webcam feed as to preserve the privacy of the parent.
Does anybody know how to add a background colour, whilst still being able to track colour?
import processing.video.*;
Capture video;
final int TOLERANCE = 20;
float XRc = 0;// XY coordinate of the center of the first target
float YRc = 0;
float XRh = 0;// XY coordinate of the center of the second target
float YRh = 0;
int ii=0; //Mouse click counter
color trackColor; //The first color is the center of the robot
color trackColor2; //The second color is the head of the robot
void setup() {
size(640,480);
video = new Capture(this,640,480);
video.start();
trackColor = color(255,0,0);
trackColor2 = color(255,0,0);
smooth();
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
video.loadPixels();
image(video,0,0);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
float r3 = red(trackColor2);
float g3 = green(trackColor2);
float b3 = blue(trackColor2);
int somme_x = 0, somme_y = 0;
int compteur = 0;
int somme_x2 = 0, somme_y2 = 0;
int compteur2 = 0;
for(int x = 0; x < video.width; x++) {
for(int y = 0; y < video.height; y++) {
int currentLoc = x + y*video.width;
color currentColor = video.pixels[currentLoc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
if(dist(r1,g1,b1,r2,g2,b2) < TOLERANCE) {
somme_x += x;
somme_y += y;
compteur++;
}
else if(compteur > 0) {
XRc = somme_x / compteur;
YRc = somme_y / compteur;
}
if(dist(r1,g1,b1,r3,g3,b3) < TOLERANCE) {
somme_x2 += x;
somme_y2 += y;
compteur2++;
}
else if(compteur2 > 0) {
XRh = somme_x2 / compteur2;
YRh = somme_y2 / compteur2;
}
}
}
if(XRc != 0 || YRc != 0) { // Draw a circle at the first target
fill(trackColor);
strokeWeight(0.05);
stroke(0);
ellipse(XRc,YRc,20,20);
}
if(XRh != 0 || YRh != 0) {// Draw a circle at the second target
fill(trackColor2);
strokeWeight(0.05);
stroke(0);
ellipse(XRh,YRh,20,20);
}
}
void mousePressed() {
if (mousePressed && (mouseButton == RIGHT)) { // Save color where the mouse is clicked in trackColor variable
if(ii==0){
if (mouseY>480){mouseY=0;mouseX=0;}
int loc = mouseX + mouseY*video.width;
trackColor = video.pixels[loc];
ii=1;
}
else if(ii==1){
if (mouseY>480){mouseY=0;mouseX=0;}
int loc2 = mouseX + mouseY*video.width;
trackColor2 = video.pixels[loc2];
ii=2;
}
}
}
Try adding the background(0); right before you draw the first circle. It should cover the video and you can draw the circles on top of it.
Regards
Jose

Why are these shapes the wrong color?

So I'm writing up a processing sketch to test a randomized terrain generator for a scorched earth clone I'm working on. It seems to work as intended but with one minor problem. In the code I generate 800 1 pixel wide rectangles and set the fill to brown beforehand. The combination of the rectangles should be a solid mass with a brown dirt-like color (77,0,0).
However, the combination shows up as black regardless of the rgb fill value set. I think it might have something to do with each rectangle's border being black? Does anyone know what is happening here offhand?
final int w = 800;
final int h = 480;
void setup() {
size(w, h);
fill(0,128,255);
rect(0,0,w,h);
int t[] = terrain(w,h);
fill(77,0,0);
for(int i=0; i < w; i++){
rect(i, h, 1, -1*t[i]);
}
}
void draw() {
}
int[] terrain(int w, int h){
width = w;
height = h;
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
//allocating horizon for screen width
int[] horizon = new int[width];
double[] skyline = new double[width];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for(int i = 0; i < n*2 ; i ++){
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*height);
for(int i = 0 ; i < width; i ++){
skyline[i] = 0;
for(int j = 0; j < n; j++){
skyline[i] += ( sin( (f[j]*PI*i/height) ) + cos(f[j+n]*PI*i/height) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (height/2);
skyline[i] = (int)skyline[i];
horizon[i] = (int)skyline[i];
}
return horizon;
}
I think it might have something to do with each rectangle's border being black?
I believe this is the case. In your setup() function, I added the noStroke() function before you draw the rectangles. This removes the black outline to the rectangles. Since each rectangle is only 1 pixel wide, having this black stroke (which is on by default) makes the color of each rectangle black, no matter what color you try to choose before.
Here is an updated setup() function - I now see a reddish brown terrain:
void setup() {
size(w, h);
fill(0, 128, 255);
rect(0, 0, w, h);
int t[] = terrain(w, h);
fill(77, 0, 0);
noStroke(); // here
for (int i=0; i < w; i++) {
rect(i, h, 1, -1*t[i]);
}
}

Lanczos Resampling error

I have written an image resizer using Lanczos re-sampling. I've taken the implementation straight from the directions on wikipedia. The results look good visually, but for some reason it does not match the result from Matlab's resize with Lanczos very well (in pixel error).
Does anybody see any errors? This is not my area of expertise at all...
Here is my filter (I'm using Lanczos3 by default):
double lanczos_size_ = 3.0;
inline double sinc(double x) {
double pi = 3.1415926;
x = (x * pi);
if (x < 0.01 && x > -0.01)
return 1.0 + x*x*(-1.0/6.0 + x*x*1.0/120.0);
return sin(x)/x;
}
inline double LanczosFilter(double x) {
if (std::abs(x) < lanczos_size_) {
double pi = 3.1415926;
return sinc(x)*sinc(x/lanczos_size_);
} else {
return 0.0;
}
}
And my code to resize the image:
Image Resize(Image& image, int new_rows, int new_cols) {
int old_cols = image.size().cols;
int old_rows = image.size().rows;
double col_ratio =
static_cast<double>(old_cols)/static_cast<double>(new_cols);
double row_ratio =
static_cast<double>(old_rows)/static_cast<double>(new_rows);
// Apply filter first in width, then in height.
Image horiz_image(new_cols, old_rows);
for (int r = 0; r < old_rows; r++) {
for (int c = 0; c < new_cols; c++) {
// x is the new col in terms of the old col coordinates.
double x = static_cast<double>(c)*col_ratio;
// The old col corresponding to the closest new col.
int floor_x = static_cast<int>(x);
horiz_image[r][c] = 0.0;
double weight = 0.0;
// Add up terms across the filter.
for (int i = floor_x - lanczos_size_ + 1; i < floor_x + lanczos_size_; i++) {
if (i >= 0 && i < old_cols) {
double lanc_term = LanczosFilter(x - i);
horiz_image[r][c] += image[r][i]*lanc_term;
weight += lanc_term;
}
}
// Normalize the filter.
horiz_image[r][c] /= weight;
// Strap the pixel values to valid values.
horiz_image[r][c] = (horiz_image[r][c] > 1.0) ? 1.0 : horiz_image[r][c];
horiz_image[r][c] = (horiz_image[r][c] < 0.0) ? 0.0 : horiz_image[r][c];
}
}
// Now apply a vertical filter to the horiz image.
Image new_image(new_cols, new_rows);
for (int r = 0; r < new_rows; r++) {
double x = static_cast<double>(r)*row_ratio;
int floor_x = static_cast<int>(x);
for (int c = 0; c < new_cols; c++) {
new_image[r][c] = 0.0;
double weight = 0.0;
for (int i = floor_x - lanczos_size_ + 1; i < floor_x + lanczos_size_; i++) {
if (i >= 0 && i < old_rows) {
double lanc_term = LanczosFilter(x - i);
new_image[r][c] += horiz_image[i][c]*lanc_term;
weight += lanc_term;
}
}
new_image[r][c] /= weight;
new_image[r][c] = (new_image[r][c] > 1.0) ? 1.0 : new_image[r][c];
new_image[r][c] = (new_image[r][c] < 0.0) ? 0.0 : new_image[r][c];
}
}
return new_image;
}
Here is Lanczosh in one single loop. no errors.
Uses mentioned at top procedures.
void ResizeDD(
double* const pixelsSrc,
const int old_cols,
const int old_rows,
double* const pixelsTarget,
int const new_rows, int const new_cols)
{
double col_ratio =
static_cast<double>(old_cols) / static_cast<double>(new_cols);
double row_ratio =
static_cast<double>(old_rows) / static_cast<double>(new_rows);
// Now apply a filter to the image.
for (int r = 0; r < new_rows; ++r)
{
const double row_within = static_cast<double>(r)* row_ratio;
int floor_row = static_cast<int>(row_within);
for (int c = 0; c < new_cols; ++c)
{
// x is the new col in terms of the old col coordinates.
double col_within = static_cast<double>(c)* col_ratio;
// The old col corresponding to the closest new col.
int floor_col = static_cast<int>(col_within);
double& v_toSet = pixelsTarget[r * new_cols + c];
v_toSet = 0.0;
double weight = 0.0;
for (int i = floor_row - lanczos_size_ + 1; i <= floor_row + lanczos_size_; ++i)
{
for (int j = floor_col - lanczos_size_ + 1; j <= floor_col + lanczos_size_; ++j)
{
if (i >= 0 && i < old_rows && j >= 0 && j < old_cols)
{
const double lanc_term = LanczosFilter(row_within - i + col_within - j);
v_toSet += pixelsSrc[i * old_rows + j] * lanc_term;
weight += lanc_term;
}
}
}
v_toSet /= weight;
v_toSet = (v_toSet > 1.0) ? 1.0 : v_toSet;
v_toSet = (v_toSet < 0.0) ? 0.0 : v_toSet;
}
}
}
The line
for (int i = floor_x - lanczos_size_ + 1; i < floor_x + lanczos_size_; i++)
should be
for (int i = floor_x - lanczos_size_ + 1; i <= floor_x + lanczos_size_; i++)
Do not know but perhaps other mistakes linger too.
I think there is a mistake in your sinc function. Below the fraction bar you have to square pi and x. Additional you have to multiply the function with lanczos size
L(x) = **a***sin(pi*x)*sin(pi*x/a) * (pi**²**x**²**)^-1
Edit: My mistake, there is all right.

Resources