To resume. the code I ve written below doesn t get me a blur image. But a black IMAGE instead ( except for the pixel edges).
For testing i ve just tried the interior PIXELS, without edges RGBTRIPLE pixels because I wanted to see if I was making well so far.
Could anybody tell me whats wrong with my code, please?
is muy BUFFER RGB newImage correct done?? if image[height][width].rgbtRed it means that newImage[height][width].rgbtRed will exist?? thanks in advance
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
//create a buffer to allocate new pixels.
RGBTRIPLE newImage[height][width];
// iterate through each row
for (int i = 0 ; i < height ; i++)
{
// iterate through each column passing through every RGBTRIPLE
for ( int j = 0; j < width ; j++)
{
int redSum = 0;
int greenSum = 0;
int blueSum = 0;
//counter for pixels being add in every avg.
//int count = 0;
// take the average amount of RGB of every pixel in a range of 3x3 pixels
// avg for left top corner
/*if ( r == 0 && l == 0) {
}
// avg left bottom corner
else if ( r == height - 1 && l == 0 ){
}
// avg right top corner
else if ( r == 0 && l == width - 1){
}
// avg left bottom corner
else if ( r == height - 1 && l == width - 1){
}
// avg top side
else if ( r == 0 && l > 0 && l != width - 1) {
}
// avg right side
else if ( l == width - 1 && r > 0 && r != height - 1) {
}
// avg bottom side
else if ( r == height - 1 && l > 0 && l != width - 1) {
}
// avg left side
else if ( l == 0 && r > 0 && r != height - 1){
}*/
for ( int iy = -1 ; iy >= 1 ; iy++)
{
for ( int jx = -1 ; jx >= 1 ; jx++)
{
redSum = redSum + image[i + iy][j + jx].rgbtRed;
greenSum = greenSum + image[i + iy][j + jx].rgbtGreen;
blueSum = blueSum + image[i + iy][j + jx].rgbtBlue;
//count++;
}
}
int avgRed = redSum / 9;
int avgGreen = greenSum / 9;
int avgBlue = blueSum / 9;
newImage[i][j].rgbtRed = avgRed;
newImage[i][j].rgbtGreen = avgGreen;
newImage[i][j].rgbtBlue = avgBlue;
}
}
for ( int y = 1 ; y < height - 1; y++)
{
for ( int x = 1; x < width - 1; x++)
{
image[y][x].rgbtRed = newImage[y][x].rgbtRed;
image[y][x].rgbtGreen = newImage[y][x].rgbtGreen;
image[y][x].rgbtBlue = newImage[y][x].rgbtBlue;
}
}
return;
}
A major mistake not already mentioned in a comment is that redSum, greenSum and blueSum are initialized to 0 only once, while they must be set to zero before each pixel is processed, so better move the definitions right before the for ( int py = 0 ; py >= 2 ; py++) loop.
It's hardly believable how the many eyes (including mine) who looked at the code could overlook the main, simple error - the inner loops (in their original as well as in the edited version) are never executed:
for ( int iy = -1 ; iy >= 1 ; iy++)
{
for ( int jx = -1 ; jx >= 1 ; jx++)
Of course, the iy >= 1 condition is false from the start; you surely meant iy <= 1 and jx <= 1.
Related
I am receiving a Segmentation fault (core dumped) error when trying to blur an image, but I cannot find out why. To achieve a blur, I loop through each element in the 2x2 image array. I then check each of the 9x9 squares around & including it - if they exist, their RGB values are added to a sum (sumRed, sumGreen, sumBlue) for each color. I also increment a counter called numPixel each time this is successful so I can average the RGB values at the end.
There are other parts of the code, but I am certain that this blur() function is causing the segfault. This is because when I comment out the body of the function, the segfault goes away.
However, within the function I do not see what is triggering the segfault. I don't think I'm going out of bound in an array, which has been the cause of most of my segfaults in the past. From commenting out certain portions of the code, I also gathered that memcpy() is not the cause of the error (or at least not the only cause).
There's also a custom header file, which includes definitions for BYTE and RGBTRIPLE:
typedef uint8_t BYTE;
...
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
The actual code is:
// TODO: Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE new_image[height][width];
BYTE sumRed, sumGreen, sumBlue;
BYTE numPixels;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; w++)
{
sumRed = sumGreen = sumBlue = 0;
numPixels = 0;
// Check from 1 higher to 1 lower
for (int h = i - 1; h <= i + 1; h++)
{
// Check from 1 left to 1 right
for (int w = j - 1; w <= j + 1; j++)
{
// If neither index is out of bound, add neighboring RGB values
if (0 <= h < height && 0 <= w < width)
{
sumRed += image[h][w].rgbtRed;
sumGreen += image[h][w].rgbtGreen;
sumBlue += image[h][w].rgbtBlue;
numPixels++;
}
}
}
new_image[i][j].rgbtRed = (BYTE) sumRed / numPixels;
new_image[i][j].rgbtGreen = (BYTE) sumGreen / numPixels;
new_image[i][j].rgbtBlue = (BYTE) sumBlue / numPixels;
}
}
memcpy(&image[0][0], &new_image[0][0], sizeof(image[0][0]) * height * width);
return;
}
Be sure of your logic, not relying on braces to save the day. Use simple short names in "local context". "Ease of reading" trumps being "Overly explicit."
for (int h = 0; h < height; h++)
for (int w = 0; w < width; w++) {
// bigger accumulators, short names, declared & init'd locally
uint16_t sumR = 0;
uint16_t sumG = 0;
uint16_t sumB = 0;
int nPix = 0;
for (int hO = -1; hO <= 1; hO++) // height offset range
for (int wO = -1; wO <= 1; wO++) { // width offset range
int indH = h + hO; // Simple!
int indW = w + wO;
if (0 <= indH && indH < height && 0 <= indW && indW < width) {
RGBTRIPLE *p = &image[ indH ][ indW ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
new_image[i][j].rgbtRed = (BYTE)( sumR / nPix );
new_image[i][j].rgbtGreen = (BYTE)( sumG / nPix );
new_image[i][j].rgbtBlue = (BYTE)( sumB / nPix );
}
/* memcpy....*/
I'm still uneasy with possible confusion between "Height/width" and "vertical/Horizontal".
Here's an alternative for the two inner loops. Don't bother to set-up the width if the height is out-of-frame...
// From -1 offset, examine >>3<< pixels: -1, 0, 1...
for( int ih = h-1, limH = ih+3; ih < limH; ih++ ) { // height range
if( ih < 0 || height <= ih ) continue;
for( int iw = w-1, limW = iw+3; iw < limW; iw++) { // width range
if( iw < 0 || width <= iw ) continue;
RGBTRIPLE *p = &image[ ih ][ iw ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
Hey, so I been stuck on the cs50 pst4 for a while now, specifically on blur.
The goal is to create a filter which blurs the image by changing each pixel to the average of the ones surrounding it.
What I did first is create a copy of the image so that I wouldn't use the changed pixels when calculating the average.
To calculate the sides and the corners i made the colors of pixels outside of the picture to 0. Then I could blindly add it and divide by however many pixels are there for ex. corners have 4 pixels surrounding it so i divide by 4, edges by 6 etc.
To get the positions I looped around image[i][j] from [i - 1][j - 1] to [i + 1][j + 1]
However it seems that the right and bottom right side aren't being calculated correctly.
#include "helpers.h"
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
for(int n = 0; n < 9; n++)
{
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
}
int rgbtRed, rgbtGreen, rgbtBlue;
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
bool corner = false;
rgbtRed = rgbtGreen = rgbtBlue = 0;
for(int n = i - 1; n <= i + 1; n++)
{
for (int k = j - 1; k <= j + 1; k++)
{
if(n < 0 || n > height || k < 0 || k > width)
{
copy[n][k].rgbtRed = copy[n][k].rgbtGreen = copy[n][k].rgbtBlue = 0;
}
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
}
}
if ((i == 0 && (j == 0 || j == width)) || (i == height && (j == 0 || j == width)))
{
image[i][j].rgbtRed = (rgbtRed / 4);
image[i][j].rgbtGreen = (rgbtGreen / 4);
image[i][j].rgbtBlue = (rgbtBlue / 4);
corner = true;
}
else if (!corner && (i == 0 || i == height || j == 0 || j == width))
{
image[i][j].rgbtRed = (rgbtRed / 6);
image[i][j].rgbtGreen = (rgbtGreen / 6);
image[i][j].rgbtBlue = (rgbtBlue / 6);
}
else
{
image[i][j].rgbtRed = (rgbtRed / 9);
image[i][j].rgbtGreen = (rgbtGreen / 9);
image[i][j].rgbtBlue = (rgbtBlue / 9);
}
}
}
Thankful for anyhelp provided
From the question it is not clear how the right and bottom right side aren't being calculated correctly. I run the your code and the output is decent from my point of view. Though it gives some runtime error.
Here are some suggestions.
if (n < 0 || n > height || k < 0 || k > width)
{
copy[n][k].rgbtRed = copy[n][k].rgbtGreen = copy[n][k].rgbtBlue = 0;
}
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
I think you are trying to setup a special handling for the boundary case. For the upper limit, isn't it should be n >= height, since it is zero-based index? Moreover, you don't have to explicitly set the pixel to black. Just ignore it and don't add them to the average value is fine. But you didn't stop there and followed by rgbtRed += copy[n][k].rgbtRed. n could be -1 or > height, it could hit array index out of bound.
Also, you setup a if statement with 3 conditions for edge, corner, and inbound case. You don't need that. You only need to know how many pixel are inbound. Take that number as the divisor for the average formula. Below is my example.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int n = 0; n < 9; n++)
{
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
}
int rgbtRed, rgbtGreen, rgbtBlue;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rgbtRed = rgbtGreen = rgbtBlue = 0;
// number of pixel is within boundary
int inbound = 0;
for (int n = i - 1; n <= i + 1; n++)
{
for (int k = j - 1; k <= j + 1; k++)
{
if (n >= 0 && n < height && k >= 0 && k < width)
{
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
inbound++;
}
}
}
image[i][j].rgbtRed = (rgbtRed / inbound);
image[i][j].rgbtGreen = (rgbtGreen / inbound);
image[i][j].rgbtBlue = (rgbtBlue / inbound);
}
}
}
$ ./filter -b ./images/courtyard.bmp outfile.bmp
Result
I have a matrix of 0 and 1
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 1 1 0 1 1 1 0 0
0 0 0 1 1 1 1 0 0 0
0 0 0 1 1 1 1 1 1 1
0 0 1 1 1 1 1 0 0 0
0 0 0 0 1 1 0 1 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0
I want to calculate the shortest distance of each item from the non-empty edges. You can assume it as pixels of black and white (or empty). We want to calculate the distance of each black pixel from the edge of the black body (through a straight line; horizontal, vertical or diagonal).
The distance is calculated geometrically: the distance of Ai,j and Ai+1,j+1 is sqrt(2).
With the following code in C, I started to calculate the distance of each item from its horizontal and vertical edges (in four directions). Now I want to consider diagonal distance too (at any angle, not just 45°).
The straightforward approach is to calculate the distance of each item from each edge. However, as the matrix gets larger, the loops become painfully slow.
Since we have the distance from horizontal and vertical edges for each item, I look for a hack to find the shortest distance to the edge by examining neighbour items in fewer checks.
#include <stdlib.h>
#include <stdio.h>
int min(int a, int b, int c, int d)
{
int e = a < b ? a : b;
int f = c < d ? c : d;
int r = e < f ? e : f;
return r;
}
int main()
{
int width = 50;
int height = 50;
int points[width][height];
int distances[width][height][5]; // 0 left 1 right 2 bottom 3 top 4 min
// some random data
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
points[x][y] = rand() % 2;
}
}
// scanning in four direction to check if the previous neighbour exists
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
if (x > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
else
{
distances[x][y][0] = 1;
}
}
}
for (int x = width - 1; x >= 0; x--)
{
if (points[x][y] > 0)
{
if (x < width - 1)
{
distances[x][y][1] = distances[x + 1][y][1] > 0 ? distances[x + 1][y][1] + 1 : 1;
}
else
{
distances[x][y][1] = 1;
}
}
}
}
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (points[x][y] > 0)
{
if (y > 0)
{
distances[x][y][2] = distances[x][y - 1][2] > 0 ? distances[x][y - 1][2] + 1 : 1;
}
else
{
distances[x][y][2] = 1;
}
}
}
for (int y = height - 1; y >= 0; y--)
{
if (points[x][y] > 0)
{
if (y < height - 1)
{
distances[x][y][3] = distances[x][y + 1][3] > 0 ? distances[x][y + 1][3] + 1 : 1;
}
else
{
distances[x][y][3] = 1;
}
}
}
}
// finding the minimum of four distances
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][4] = min(distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3]);
printf("%d %d %d %d %d %d %d \n", x, y, distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3], distances[x][y][4]);
}
}
}
return 0;
}
If I understood correctly, given an arbitrary body as the ameba-like shown below, you would like to find the shortest distance from its containing points (for instance, the black point in the figure below) to the edges of the black body. This is the distance shown in blue. And you would like to hopefully take advantage of the orthogonal distances already calculated (black straight lines in the figure) to find it quickly.
Since the shape is arbitrary and not many assumptions can be made about it, the only thing I could think of is to confine the search for the shortest distance to the bounding square shown below in green. The value of the green square side is two times the shortest orthogonal distance found in your algorithm (from the black point to the green point).
Another possible approach would be to get instead a 1/8, 1/4 or so of the size of this green square and if no edges are found, keep increasing it until you find one with a few edges. It is guaranteed that at least the last green square will have at least one edge point, which is the orthogonal distance itself.
Playing with some strategy to grow the green square, maybe you can get a satisfactory performance heuristically.
This solution is easier said than done when it comes to put it in code, but I'm not quite sure I got the problem correctly so I stopped here.
One issue I found is that the term "black body" is not well defined, and the matrix shown in the question does not have any sparse points so it's not random at all as the posted code generates. Does the black body allow holes in it? Even the word "edge" is confusing to me because my English is not very good and the term reminds me of the term used in graph theory which is actually a line segment.
I tried the code and its output seems correct and clear. Just noticed some rubbish is coming out from the not initialized distances variable. Easier to get this if you reduce the size of points array to 10x10 or so.
EDIT:
Here is a possible implementation of the first method. The function that calculates the shortest distance to the edge, taking into account a bounding square, is the get_min_dist_to_edge function. All edges are added to a list to reduce unnecessary checks. To get the first point of the list inside the bounding square, there is no way other than iterating the list from the beginning. In a use case with too many edges, this list can get too large. A hash table containing the elements of the list mapped to its y coordinate would allow to find the first element inside the square much faster, at the expense of some memory.
#include "ameba.h"
#include <sys/queue.h>
#include <search.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
struct point_entry_t {
int x;
int y;
LIST_ENTRY(point_entry_t) entries;
};
LIST_HEAD(slisthead, point_entry_t)
edges_list_head = LIST_HEAD_INITIALIZER(edges_list_head);
void add_point_to_edges_list(int x, int y)
{
static int list_initialized = 0;
if (list_initialized == 0) {
LIST_INIT(&edges_list_head);
list_initialized = 1;
}
struct point_entry_t *entry = malloc(sizeof(*entry));
if (entry) {
entry->x = x;
entry->y = y;
LIST_INSERT_HEAD(&edges_list_head, entry, entries);
}
}
void clear_list(void)
{
while (!LIST_EMPTY(&edges_list_head)) {
struct point_entry_t *n1 = LIST_FIRST(&edges_list_head);
LIST_REMOVE(n1, entries);
free(n1);
}
}
int min(int a, int b, int c, int d)
{
int e = a < b ? a : b;
int f = c < d ? c : d;
int r = e < f ? e : f;
return r;
}
int calc_distances(unsigned char points[80][80], int distances[80][80][5])
{
int width = 80;
int height = 80;
// scanning in four direction to check if the previous neighbour exists
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
if (x > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
else
{
distances[x][y][0] = 1;
}
}
}
for (int x = width - 1; x >= 0; x--)
{
if (points[x][y] > 0)
{
if (x < width - 1)
{
distances[x][y][1] = distances[x + 1][y][1] > 0 ? distances[x + 1][y][1] + 1 : 1;
}
else
{
distances[x][y][1] = 1;
}
}
}
}
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (points[x][y] > 0)
{
if (y > 0)
{
distances[x][y][2] = distances[x][y - 1][2] > 0 ? distances[x][y - 1][2] + 1 : 1;
}
else
{
distances[x][y][2] = 1;
}
}
}
for (int y = height - 1; y >= 0; y--)
{
if (points[x][y] > 0)
{
if (y < height - 1)
{
distances[x][y][3] = distances[x][y + 1][3] > 0 ? distances[x][y + 1][3] + 1 : 1;
}
else
{
distances[x][y][3] = 1;
}
}
}
}
// finding the minimum of four distances
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][4] = min(distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3]);
if (distances[x][y][4] == 1)
add_point_to_edges_list(x, y);
}
}
}
}
void print_edges_and_points(int point_x, int point_y,
int min_dist_edge_x, int min_dist_edge_y,
int distances[80][80][5])
{
for (size_t y = 0; y < 80; y++) {
for (size_t x = 0; x < 80; x++) {
if ( x == min_dist_edge_x
&& y == min_dist_edge_y) {
printf("E");
} else if (distances[x][y][4] == 1) {
printf(".");
} else if ( x == point_x
&& y == point_y) {
printf("P");
} else {
printf(" ");
}
}
printf("\n");
}
}
static inline void get_boundaries(int x, int y, int distances[80][80][5],
int *boundary_start_x, int *boundary_finish_x,
int *boundary_start_y, int *boundary_finish_y)
{
*boundary_start_x = x - distances[x][y][4];
*boundary_start_y = y - distances[x][y][4];
*boundary_finish_x = x + distances[x][y][4];
*boundary_finish_y = y + distances[x][y][4];
if (*boundary_start_x < 0) *boundary_start_x = 0;
if (*boundary_start_y < 0) *boundary_start_y = 0;
if (*boundary_finish_x > 80) *boundary_finish_x = 80;
if (*boundary_finish_y > 80) *boundary_finish_y = 80;
}
float get_min_dist_to_edge(int x, int y, int distances[80][80][5],
int *edge_x, int *edge_y)
{
uint32_t min_sq_dist = INT_MAX;
int boundary_start_x; int boundary_finish_x;
int boundary_start_y; int boundary_finish_y;
get_boundaries(x, y, distances,
&boundary_start_x, &boundary_finish_x,
&boundary_start_y, &boundary_finish_y);
if (!LIST_EMPTY(&edges_list_head)) {
struct point_entry_t *entry = NULL;
LIST_FOREACH(entry, &edges_list_head, entries) {
if ( entry->y > boundary_finish_y
|| entry->x < boundary_start_x
|| entry->x > boundary_finish_x) {
continue;
} else if (entry->y < boundary_start_y) {
return sqrt(min_sq_dist);
}
int sq_dist = pow(abs(x - entry->x), 2) +
pow(abs(y - entry->y), 2);
if (sq_dist < min_sq_dist) {
*edge_x = entry->x;
*edge_y = entry->y;
min_sq_dist = sq_dist;
}
}
}
return -1;
}
int main(int nargs, char *argv[])
{
if (nargs != 3) {
printf("\tusage: %s <x> <y>\n", argv[0]);
return 0;
}
unsigned char (*points)[80] = (unsigned char (*)[80])ameba_bin;
int distances[80][80][5] = {0,}; // 0 left 1 right 2 bottom 3 top 4 min
int x = atoi(argv[1]);
int y = atoi(argv[2]);
int min_dist_edge_x = 0;
int min_dist_edge_y = 0;
calc_distances(points, distances);
float min_dist_edge = 0;
if ((min_dist_edge = get_min_dist_to_edge(x, y, distances, &min_dist_edge_x,
&min_dist_edge_y)) > 0) {
print_edges_and_points(x, y, min_dist_edge_x, min_dist_edge_y, distances);
printf("ortho distances for P (%d, %d): < %d, > %d, ^ %d, v %d\n", x, y,
distances[x][y][0], distances[x][y][1],
distances[x][y][2], distances[x][y][3]);
printf("min distance from P (%d, %d) to nearest edge point E (%d, %d) = %.02f\n", x, y,
min_dist_edge_x, min_dist_edge_y, min_dist_edge);
}
clear_list();
return 0;
}
Here is an output example:
$ gcc main.c -lm && ./a.out 35 40
.....
.... .....
.. ..
.. ..
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
E .
........ . .
. ... . .
.. ..... .
. .
. .
. .
. P .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
.. .
. .
.. .
... .
... .
........... .
.... .
.. .
... .
... ..
.... ...
......
ortho distances for P (35, 40): < 31, > 37, ^ 28, v 24
min distance from P (35, 40) to nearest edge point E (27, 33) = 10.63
ameba.h was created using xxd -i over the output of a web-based tool that converts images to an ASCII table.
This problem is called "Euclidean Distance Transform". It can be solved exactly in O(NM) time. Here you can find a nice paper discussing the algorithm.
http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf
It works also for other norms like Manhattan or Chessboard distance.
I'm working on a image filter. On the blur filter i need to get data of the neighbor pixels of one pixel to update it's RGB values. To do so I'm using something like:
RGBTRIPLE *neighbors;
int array_size;
if (i == 0 && j == 0) {
array_size = 4;
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
neighbors[0] = image[i][j];
neighbors[1] = image[i][j + 1];
neighbors[2] = image[i + 1][j];
neighbors[3] = image[i][j + 1];
} else if (i == height - 1 && j == 0) {
array_size = 4;
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
neighbors[0] = image[i + 1][j];
neighbors[1] = image[i + 1][j + 1];
neighbors[2] = image[i][j];
neighbors[3] = image[i][j + 1];
}
And having an if statement for each case (top left, top right, bottom left, bottom right, up, left, bottom, right and no corner). But this makes the code extremely big and inefficient. Is there a better way to do so?
The RGBTRIPLE is a pixel struct defined as:
typedef uint8_t BYTE;
typedef struct {
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
If the order of data doesn't matter, you can use loops to count and collect in-range pixels.
RGBTRIPLE *neighbors;
int array_size = 0;
/* count in-range pixels */
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
if (0 <= i + k && i + k < height && 0 <= j + l && j + l < width) {
array_size++;
}
}
}
/* allocate the array */
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
if (neighbors == NULL) {
/* handle error */
}
/* collect pixel values */
int cnt = 0;
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
if (0 <= i + k && i + k < height && 0 <= j + l && j + l < width) {
neighbors[cnt++] = image[i + k][j + l];
}
}
}
And having an if statement for each case (top left, top right, bottom left, bottom right, up, left, bottom, right and no corner). But this makes the code extremely big and inefficient. Is there a better way to do so?
A common technique is to have extra room at the sides so that you can access a default value (to avoid the branches) or a tombstone value of some sort (to simplify the code).
As for slow, you would need to profile to see whether that is true or not. Most branches will be correctly predicted most of the time if the image is big enough.
If it is true that the branches are really slowing you down, then you will have to make the code more complex, e.g. splitting the processing into border/no border cases as #IanAbbott suggests.
So, I have spent about 5 hours+ trying to figure out what is wrong with my code. I have tried debug50 with a 3x3 file I have manually created in Paint and everything seemed to work as intended; each pixel makes a 3x3 sweep around itself and disregards pixels that do not exist, like the ones in the corners or around edges. The final average values for each of the colors were also correct. Somehow, though, when I checked with check50, it gave out the following message:
With countless tweaking and head-scratching, I have decided that it was probably time for me to turn to the community for help. Here's my code:
{
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
{
int avgfordiv = 0;
int neighvalgreen = 0;
int neighvalblue = 0;
int neighvalred = 0;
for (int hh = -1; hh < 2; hh++)
{
for (int ww = -1; ww < 2; ww++)
{
if ((h+hh) != height && (w+ww) != width && (h+hh) != -1 && (w+ww) != -1)
{
//sweep
avgfordiv++;//count up for division
neighvalgreen += image[h + hh][w + ww].rgbtGreen;
neighvalred += image[h + hh][w + ww].rgbtRed;
neighvalblue += image[h + hh][w + ww].rgbtBlue;
}
}
}
//add values to pixels
image[h][w].rgbtGreen = (int)(round((float)neighvalgreen / avgfordiv));
image[h][w].rgbtBlue = (int)(round((float)neighvalblue / avgfordiv));
image[h][w].rgbtRed = (int)(round((float)neighvalred / avgfordiv));
//check cap
if (image[h][w].rgbtGreen <= 255)
{}
else
image[h][w].rgbtGreen %= 255;
if (image[h][w].rgbtRed <= 255)
{}
else
image[h][w].rgbtRed %= 255;
if (image[h][w].rgbtBlue <= 255)
{}
else
image[h][w].rgbtBlue %= 255;
}
}
return;
}
Making a copy of the image and using that copy to calculate the total amount of red green and blue seems to fix it.
RGBTRIPLE copy[height][width];
for (int h = 0; h < height; i++)
{
for (int w = 0; w < width; j++)
{
copy[h][w] = image[h][w];
}
}
And change it below:
neighvalgreen += copy[h + hh][w + ww].rgbtGreen;
neighvalred += copy[h + hh][w + ww].rgbtRed;
neighvalblue += copy[h + hh][w + ww].rgbtBlue;
Also you dont need to check if the values exceeded 255 because you are calculating the average value so it will never exceeded 255.
My strategy in pseudocode is as follows:
Save entire image as a tmp
loop through every single pixel
For every pixel, image a 3x3 square with the said pixel at the center. Check each of the pixel of the 3x3 square if it exists. If it does, add up the sum. Finally calculate average
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
//store entire image in tmp to maintain original value
RGBTRIPLE tmp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
tmp[i][j] = image[i][j];
}
}
//loop through each pixel
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float n = 0, r = 0, b = 0, g = 0;
// loop the 9box
for (int ii = 0; ii < 3; ii++)
{
for (int jj = 0; jj < 3; jj++)
{
//calculate average. ONLY if that pixel exists.
if ((i + ii - 1 >= 0 && i + ii - 1 < height) && (j + jj - 1 >= 0 && j + jj - 1 < width))
{
b = b + (float)tmp[i + ii - 1][j + jj - 1].rgbtBlue;
r = r + (float)tmp[i + ii - 1][j + jj - 1].rgbtRed;
g = g + (float)tmp[i + ii - 1][j + jj - 1].rgbtGreen;
n++;
}
}
}
//calculate
image[i][j].rgbtBlue = (int)round(b / n);
image[i][j].rgbtRed = (int)round(r / n);
image[i][j].rgbtGreen = (int)round(g / n);
}
}
return;
}
I have written a completely different code and got the same error and the same numbers.
But someone wrote this code which works perfectly:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE ogImage[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
ogImage[i][j] = image[i][j];
}
}
for (int i = 0, red, green, blue, counter; i < height; i++)
{
for (int j = 0; j < width; j++)
{
red = green = blue = counter = 0;
if (i >= 0 && j >= 0)
{
red += ogImage[i][j].rgbtRed;
green += ogImage[i][j].rgbtGreen;
blue += ogImage[i][j].rgbtBlue;
counter++;
}
if (i >= 0 && j - 1 >= 0)
{
red += ogImage[i][j-1].rgbtRed;
green += ogImage[i][j-1].rgbtGreen;
blue += ogImage[i][j-1].rgbtBlue;
counter++;
}
if ((i >= 0 && j + 1 >= 0) && (i >= 0 && j + 1 < width))
{
red += ogImage[i][j+1].rgbtRed;
green += ogImage[i][j+1].rgbtGreen;
blue += ogImage[i][j+1].rgbtBlue;
counter++;
}
if (i - 1 >= 0 && j >= 0)
{
red += ogImage[i-1][j].rgbtRed;
green += ogImage[i-1][j].rgbtGreen;
blue += ogImage[i-1][j].rgbtBlue;
counter++;
}
if (i - 1 >= 0 && j - 1 >= 0)
{
red += ogImage[i-1][j-1].rgbtRed;
green += ogImage[i-1][j-1].rgbtGreen;
blue += ogImage[i-1][j-1].rgbtBlue;
counter++;
}
if ((i - 1 >= 0 && j + 1 >= 0) && (i - 1 >= 0 && j + 1 < width))
{
red += ogImage[i-1][j+1].rgbtRed;
green += ogImage[i-1][j+1].rgbtGreen;
blue += ogImage[i-1][j+1].rgbtBlue;
counter++;
}
if ((i + 1 >= 0 && j >= 0) && (i + 1 < height && j >= 0))
{
red += ogImage[i+1][j].rgbtRed;
green += ogImage[i+1][j].rgbtGreen;
blue += ogImage[i+1][j].rgbtBlue;
counter++;
}
if ((i + 1 >= 0 && j - 1 >= 0) && (i + 1 < height && j - 1 >= 0))
{
red += ogImage[i+1][j-1].rgbtRed;
green += ogImage[i+1][j-1].rgbtGreen;
blue += ogImage[i+1][j-1].rgbtBlue;
counter++;
}
if ((i + 1 >= 0 && j + 1 >= 0) && (i + 1 < height && j + 1 < width))
{
red += ogImage[i+1][j+1].rgbtRed;
green += ogImage[i+1][j+1].rgbtGreen;
blue += ogImage[i+1][j+1].rgbtBlue;
counter++;
}
image[i][j].rgbtRed = round(red / (counter * 1.0));
image[i][j].rgbtGreen = round(green / (counter * 1.0));
image[i][j].rgbtBlue = round(blue / (counter * 1.0));
}
}
return;
}
I know it's late but maybe it will be helpful for somebody.
For future people in doubt
You don't need that much conditions, just think that you are working with one matrix within another.
Once this is done, just place a condition, in case the location being worked does not exceed the matrix limits.
Example
current line + the submatrix line cannot be less than zero, because that would be going beyond the limits.
L: matrix line
sL: submatrix line
[L + sL] [0] ! < 0
[0 + (-1) [0] would be extrapolating.
Just think now for the other cases as well.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// average of the ORIGINAL value of the pixels around it
int avgR, avgG, avgB, counter;
// make a copy of the original image for the calculations
RGBTRIPLE copy[height][width];
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
{
copy[h][w] = image[h][w];
}
}
// go across the image
for (int linha = 0; linha < height; linha++)
{
for (int coluna = 0; coluna < width; coluna++)
{
// initialize the variables and reset them to 0
avgR = 0;
avgG = 0;
avgB = 0;
counter = 0;
// go across the pixels around
for (int row = -1; row < 2; row++)
{
for (int column = -1; column < 2; column++)
{
if (linha + row < 0 || coluna + column < 0 || linha + row >= height || coluna + column >= width)
{
}
else
{
avgR += copy[linha + row][coluna + column].rgbtRed;
avgG += copy[linha + row][coluna + column].rgbtGreen;
avgB += copy[linha + row][coluna + column].rgbtBlue;
counter ++;
}
}
}
image[linha][coluna].rgbtRed = round(avgR / (float) counter);
image[linha][coluna].rgbtGreen = round(avgG / (float) counter);
image[linha][coluna].rgbtBlue = round(avgB / (float) counter);
}
}
return;
}
Fernando's answer is great (I don't have the rep to comment directly on it), but to handle the edge cases, I turned the pixel's for loop's start and end points into variables that get adjusted if you're working with an edge ("i" and "j" are my outer loop counters):
int startRow = -1;
int endRow = 1;
int startColumn = -1;
int endColumn = 1;
// Handle edge cases
if (i + startRow < 0) { startRow = 0; }
if (j + startColumn < 0) { startColumn = 0; }
if (i + endRow >= height) { endRow = 0; }
if (j + endColumn >= width) { endColumn = 0; }
// go across the pixels around
for (int pxRow = startRow; pxRow <= endRow; pxRow++) {
for (int pxColumn = startColumn; pxColumn <= endColumn; pxColumn++) {
int row = i + pxRow;
int column = j + pxColumn;
avgR += copy[row][column].rgbtRed;
avgG += copy[row][column].rgbtGreen;
avgB += copy[row][column].rgbtBlue;
counter ++;
}
}