英文:
Review on code from CS50x Problem Set 4 "Filter More" (Grayscale and Blur functions)
问题
第一个问题 - 我已经创建了一个用于将图像转换为灰度的函数,但由于某种原因,它不会将平均值(3个颜色值除以3)四舍五入。
我在不同的地方(计算平均值和分配'阴影'的值给像素时)使用了round()
函数,我也尝试了ceil()
函数,但无论如何都不起作用。
第二个问题 - 我已经创建了一个用于模糊图像的函数(在像素周围创建一个3x3的'框',并根据红、绿和蓝的平均值来计算平均值,然后将新的颜色值分配给3x3 '框'中心的像素)。但是,'check50'告诉我我做得完全错误。
我的代码中是否有严重错误,还是它只是不适用于这些特定的测试?
关于灰度处理的代码:
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int shade = 0;
shade = ceil((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3);
image[i][j].rgbtRed = shade; //也尝试了round(shade)和ceil(shade)
image[i][j].rgbtGreen = shade;
image[i][j].rgbtBlue = shade;
}
}
return;
}
关于模糊处理的代码:
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp[height][width]; // 临时数组
for (int i = 0; i < height; i++) // 复制到临时数组
{
for (int j = 0; j < width; j++)
{
temp[i][j].rgbtRed = image[i][j].rgbtRed;
temp[i][j].rgbtGreen = image[i][j].rgbtGreen;
temp[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
for (int i = 0; i <= height; i++)
{
for (int j = 0; j <= width; j++) // 遍历像素数组
{
unsigned int avgR = 0, avgG = 0, avgB = 0; // 平均颜色值 = 0
unsigned int count = 0; // 用于记录使用了多少像素
for (int k = (i - 1); k <= i + 1; k++) // 模糊的边界(3x3)
{
for (int l = (j - 1); l < j + 1; l++) // 边界
{
if (k >= 0 && k <= (height - 1) && l >= 0 && l <= (width - 1)) // 检查像素是否存在
{
avgR += round(temp[k][l].rgbtRed); // 计算平均值
avgG += round(temp[k][l].rgbtGreen);
avgB += round(temp[k][l].rgbtBlue);
count++; // 使用的像素计数
}
}
}
image[i][j].rgbtRed = round(avgR / count); // 用平均值重写原始颜色
image[i][j].rgbtGreen = round(avgG / count);
image[i][j].rgbtBlue = round(avgB / count);
}
}
return;
}
我已经尝试过:在灰度处理中更改round()
和ceil()
函数的位置,尝试将'shade'变量设置为float
类型。至于模糊处理,我没有改动任何东西,因为它完全错误,所以我不知道从哪里开始:(也许问题在于我试图尽可能少地“硬编码”,所以我在尝试通过循环自动化所有过程时犯了一些错误。
英文:
description of tasks: https://cs50.harvard.edu/x/2023/psets/4/filter/more/
There are two problems:
First one - I've made a function to GRAYSCALE a picture, but for some reason it doesn't round the value of average (3 color values divided by 3).
I have used the round()
function in diferent places (when counting average and assigning the value of 'shade' to pixel), so I did with the ceil()
function, it just doesn't work no matter what.
Second one - I've made a function to BOX-BLUR the image (making a 3x3 'box' around the pixel and counting the average amount of Red Green and Blue accordingly, then assigning the new values of color to the pixel in center of 3x3 'box') But the 'check50' tells me that I'm doing it all wrong.
Is there any critical mistakes in my code or is it just doesn't situated for this specific tests?
screenshots of 'test' included:
Grayscale: first, second, third
CODE for GRAYSCALE :
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int shade = 0;
shade = ceil((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3);
image[i][j].rgbtRed = shade; **//also tried round(shade) and ceil(shade)**
image[i][j].rgbtGreen = shade;
image[i][j].rgbtBlue = shade;
}
}
return;
}
CODE for BLUR:
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp[height][width]; // temp array
for (int i = 0; i < height; i++) // copy to temporary array
{
for (int j = 0; j < width; j++)
{
temp[i][j].rgbtRed = image[i][j].rgbtRed;
temp[i][j].rgbtGreen = image[i][j].rgbtGreen;
temp[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
for (int i = 0; i <= height; i++)
{
for (int j = 0; j <= width; j++) // going through array of pixels
{
unsigned int avgR = 0, avgG = 0, avgB = 0; // average color value = 0
unsigned int count = 0; // to know how many pixels were used
for (int k = (i - 1); k <= i + 1; k++) // boundaries of blur (3x3)
{
for (int l = (j - 1); l < j + 1; l++) // boundaries
{
if (k >= 0 && k <= (height - 1) && l >= 0 && l <= (width - 1)) // checking if pixel exists
{
avgR += round(temp[k][l].rgbtRed); // calculating average
avgG += round(temp[k][l].rgbtGreen);
avgB += round(temp[k][l].rgbtBlue);
count++; // pixels used count
}
}
}
image[i][j].rgbtRed = round(avgR / count); // rewriting original color with average
image[i][j].rgbtGreen = round(avgG / count);
image[i][j].rgbtBlue = round(avgB / count);
}
}
return;
}
I've tried to: change the position of round()
and ceil()
functions in **Grayscale **, tried to make 'shade' variable a float
-type.
In Blur I didn't touch anything, because it's all wrong, so I dont know where to start
Maybe the problem is that I try to 'hardcode' as less as it is possible, so I make some mistakes while trying to automate all processes via loops
答案1
得分: 0
错误的数学操作
代码执行整数除法 avgR / count
,将其截断的整数商传递给 double round(double)
,但这没有任何有用的效果。
// image[i][j].rgbtRed = round(avgR / count);
而是应该使用整数数学进行四舍五入。可以实现各种四舍五入模式,而不使用浮点数学。
unsigned divide_round_half_way_up(unsigned a, unsigned b) {
return a / b + (a % b * 2 >= b);
}
请注意,a%b
的成本通常很小,考虑到先前的 a/b
。好的编译器会将商和余数都渲染为一个时间成本。
3个下标越界错误
// for (int i = 0; i <= height; i++) {
// for (int j = 0; j <= width; j++)pixels
// ...
// for (int l = (j - 1); l < j + 1; l++) // boundaries
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++)
for (int l = (j - 1); l <= j + 1; l++)
简化
RGBTRIPLE temp[height][width]; // 临时数组
// for (int i = 0; i < height; i++) // 复制到临时数组 {
// for (int j = 0; j < width; j++) {
// temp[i][j].rgbtRed = image[i][j].rgbtRed;
// temp[i][j].rgbtGreen = image[i][j].rgbtGreen;
// temp[i][j].rgbtBlue = image[i][j].rgbtBlue;
// }
// }
memcpy(temp, image, sizeof temp);
英文:
Wrong math
Code performs integer divisions avgR / count
with its truncated integer quotient. It then passes the integer quotient to double round(double)
for no useful effect.
// image[i][j].rgbtRed = round(avgR / count);
Instead perform rounding with integer math. Various rounding modes are possible to implement without using floating point math.
unsigned divide_round_half_way_up(unsigned a, unsigned b) {
return = a/b + (a%b*2 >= b);
}
Note that the cost of a%b
is often minute given the prior a/b
. Good compilers render both the quotient and remainder for the time cost of one.
3 Off by one bugs
// for (int i = 0; i <= height; i++) {
// for (int j = 0; j <= width; j++)pixels
// ...
// for (int l = (j - 1); l < j + 1; l++) // boundaries
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++)
for (int l = (j - 1); l <= j + 1; l++)
Simplification
RGBTRIPLE temp[height][width]; // temp array
// for (int i = 0; i < height; i++) // copy to temporary array {
// for (int j = 0; j < width; j++) {
// temp[i][j].rgbtRed = image[i][j].rgbtRed;
// temp[i][j].rgbtGreen = image[i][j].rgbtGreen;
// temp[i][j].rgbtBlue = image[i][j].rgbtBlue;
// }
// }
memcpy(temp, image, sizeof temp);
答案2
得分: 0
在灰度模式下,你应该尝试:
shade = round((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3.0);
ceil()
和 round()
都接受浮点数。使用 3.0 而不是 3 会强制 C 将其计算为浮点数。
英文:
In the grayscale, you should try:
shade = round((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3.0);
Both ceil()
and round()
take floating point. Using 3.0 instead of 3 will force C calculate it as float.
答案3
得分: -1
不需要超越第一个示例,其中您得到rgb = (27, 28, 28),应该生成(28,28,28),但得到(27,27,27)。
您正在将除法视为浮点除法,因为您使用了round
和ceil
,但在C中,int/int将执行整数除法,即立即截断所有小数部分。
您可以通过例如除以3.0
来修复这个问题,其中值将提升为双精度,保留重要的小数部分,然后按您喜欢的方式四舍五入数字。
int shade = ceil((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3.0);
和
image[i][j].rgbtRed = round(avgR / (double)count);
分别。
您还混淆了模糊代码的界限。
for (int i = 0; i <= height; i++)
这里您的i
太高了。必须小于height
。
而您的内部循环
for (int k = (i - 1); k <= i + 1; k++)
{
for (int l = (j - 1); l < j + 1; l++)
很明显,它与k
和l
的上界不一致。两者都应包括上界;l <= j + 1
。
英文:
No need to go beyond the very first example, where you get rgb = (27, 28, 28), and should produce (28,28,28), but get (27,27,27).
You are treating division as floating point division, given your use of round
and ceil
, but an int/int in C will perform integer division, i.e. truncating all decimals immediately.
You could fix that by e.g. dividing by 3.
, where the values will be promoted to a double, preserving the important decimals, then rounding off the numbers by whatever way you prefer.
int shade = ceil((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3.);
and
image[i][j].rgbtRed = round(avgR / (double)count);
respectively.
You have also messed up the bounds of in your blurring code.
for (int i = 0; i <= height; i++)
Your i
goes to high here. Must be less than height
.
And your inner loops
for (int k = (i - 1); k <= i + 1; k++)
{
for (int l = (j - 1); l < j + 1; l++)
is clear to see that it's inconsistent with the upper bounds for k
and l
. Both should include the upper bound; l <= j + 1
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论