Otsu thresholding - c

I'm trying to calculate a threshold value using Otsu's method. Sample image is 8-bit, grayscale, bmp file.
Histogram for that image generated by following:
/* INITIALIZE ARRAYS */
for(int i = 0; i < 255; i++) occurrence[i] = 0;
for(int i = 0; i < 255; i++) histogram[i] = 0;
/* START AT BEGINNING OF RASTER DATA */
fseek(input_img, (54 + 4 * color_number), SEEK_SET);
/* READ RASTER DATA */
for(int r = 0; r <= original_img.rows - 1; r++) {
for(int c = 0; c <= original_img.cols -1; c++) {
fread(p_char, sizeof(char), 1, input_img);
pixel_value = *p_char;
/* COUNT OCCURRENCES OF PIXEL VALUE */
occurrence[pixel_value] = occurrence[pixel_value] + 1;
total_pixels++;
}
}
for(int i = 0; i <= 255; i++) {
/* TAKES NUMBER OF OCCURRENCES OF A PARTICULAR PIXEL
* AND DIVIDES BY THE TOTAL NUMBER OF PIXELS YIELDING
* A RATIO */
histogram[i] = (float) occurrence[i] / (float) total_pixels;
}
Histogram then passed to function otsu_method in main:
threshold_value = otsu_method(histogram, total_pixels);
Function otsu_method:
int otsu_method(float *histogram, long int total_pixels) {
double omega[256], myu[256];
double max_sigma, sigma[256];
int threshold;
omega[0] = histogram[0];
myu[0] = 0.0;
for(int i = 1; i < 256; i++) {
omega[i] = omega[i - 1] + histogram[i];
myu[i] = myu[i - 1] + i * histogram[i];
}
threshold = 0;
max_sigma = 0.0;
for(int i = 0; i < 255; i++) {
if(omega[i] != 0.0 && omega[i] != 1.0)
sigma[i] = pow(myu[255] * omega[i], 2) / (omega[i] * (1.0 - omega[i]));
else
sigma[i] = 0.0;
if(sigma[i] > max_sigma) {
max_sigma = sigma[i];
threshold = i;
}
}
printf("Threshold value: %d\n", threshold);
return threshold;
}
And binarize image based on threshold value:
void threshold_image(FILE* input_file, FILE* output_file, unsigned long vector_size, int threshold_value) {
unsigned char* p_char;
unsigned char dummy;
struct_img binary_img;
unsigned char* binary_data;
dummy = '0';
p_char = &dummy;
binary_img.data = malloc(vector_size * sizeof(char));
if(binary_img.data == NULL) printf("Failed to malloc binary_img.data\n");
binary_data = binary_img.data;
/* CONVERT PIXEL TO BLACK AND WHITE BASED ON THRESHOLD VALUE */
for(int i = 0; i < vector_size - 1; i++) {
fread(p_char, sizeof(char), 1, input_file);
if(*p_char < threshold_value) *(binary_data + i) = 0;
else *(binary_data + i) = 255;
fwrite((binary_data + i), sizeof(char), 1, output_file);
}
/* FREE ALLOCATED MEMORY */
free(binary_data);
}
Program output:
Reading file 512gr.bmp
Width: 512
Height: 512
File size: 263222
# Colors: 256
Vector size: 262144
Total number of pixels: 262144
Threshold value: 244
I think 244 is not a properly computed threshold value, because when function threshold_image binarize image with that all pixels converted to black.
If I skip otsu_method and get threshold value from user input function threshold_image works properly.
Function otsu_method is copy-pasted code, for this reason I'm not crystal clear about variables or conditions.
I'm learning about image processing and trying to figure out basics. Any information about Otsu's algorithm and any feedback about my code helps.

I found what caused the problem and changed function otsu_method:
int otsu_method(float *histogram, long int total_pixels) {
double probability[256], mean[256];
double max_between, between[256];
int threshold;
/*
probability = class probability
mean = class mean
between = between class variance
*/
for(int i = 0; i < 256; i++) {
probability[i] = 0.0;
mean[i] = 0.0;
between[i] = 0.0;
}
probability[0] = histogram[0];
for(int i = 1; i < 256; i++) {
probability[i] = probability[i - 1] + histogram[i];
mean[i] = mean[i - 1] + i * histogram[i];
}
threshold = 0;
max_between = 0.0;
for(int i = 0; i < 255; i++) {
if(probability[i] != 0.0 && probability[i] != 1.0)
between[i] = pow(mean[255] * probability[i] - mean[i], 2) / (probability[i] * (1.0 - probability[i]));
else
between[i] = 0.0;
if(between[i] > max_between) {
max_between = between[i];
threshold = i;
}
}
return threshold;
}
What really differs:
between[i] = pow(mean[255] * probability[i] - mean[i], 2) / (probability[i] * (1.0 - probability[i]));
Program output:
Reading file 512gr.bmp
Width: 512
Height: 512
File size: 263222
# Colors: 256
Vector size: 262144
Total number of pixels: 262144
Threshold value: 117
Probability: 0.416683
Mean: 31.9631
Between varaince: 1601.01

Related

Super-sampling anti-aliasing for a curve via libpng

I tried to smoothen a line via the super-sampling anti-aliasing technique by adding transparency to neighboring pixels. Here is the code in C
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <png.h>
#define WIDTH 512
#define HEIGHT 512
int main()
{
// Image buffer
unsigned char image[HEIGHT][WIDTH][4];
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
image[i][j][0] = 255;
image[i][j][1] = 255;
image[i][j][2] = 255;
image[i][j][3] = 0;
}
}
// A sample curve
for (double x = -M_PI; x <= M_PI; x += M_PI / WIDTH)
{
int y = (int)(HEIGHT / 2 - sin(x) * cos(x) * HEIGHT / 2);
int i = (int)(x * WIDTH / (2 * M_PI) + WIDTH / 2);
// The anti-aliasing part
int sample = 2; // how far we are sampling
double max_distance = sqrt(sample * sample + sample * sample);
for (int ii = -sample; ii <= sample; ii++)
{
for (int jj = -sample; jj <= sample; jj++)
{
int iii = i + ii;
int jjj = y + jj;
if (iii >= 0 && iii < WIDTH && jjj >= 0 && jjj < HEIGHT)
{
// Here is my question
int alpha = 255 - (int)(100.0 * sqrt(ii * ii + jj * jj) / max_distance);
image[jjj][iii][0] = 0;
image[jjj][iii][1] = 0;
image[jjj][iii][2] = 0;
image[jjj][iii][3] = alpha > image[jjj][iii][3] ? alpha : image[jjj][iii][3];
}
}
}
}
FILE *fp = fopen("curve.png", "wb");
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info = png_create_info_struct(png);
png_init_io(png, fp);
png_set_IHDR(png, info, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png, info);
for (int i = 0; i < HEIGHT; i++)
{
png_write_row(png, (png_bytep)image[i]);
}
png_write_end(png, NULL);
fclose(fp);
return 0;
}
Although it does some smoothing, but the result is far from the available programs. Where did I do wrong?
I tried to calculate the transparency based on the distance of each neighboring pixel from the center of the line:
int alpha = 255 - (int)(100.0 * sqrt(ii * ii + jj * jj) / max_distance);
I used the factor of 100 instead of 255 since we do not need to go deep into full transparency.
The problem is how to set the alpha value for each pixel based on neighboring pixels when the transparency of each neighbor is subject to change according to its neighbors?

C - BMP - Edge Detection Algorithm returns bmp which only displays 1/3 of the image

i have to code a sudoku ocr for school in C.
I use an edge detection algorithm which returns a bmp file.
However, the returned file only shows 1/3 of the expected output.
Please can someone tell me what is wrong in my code :)
input image (BMP file)
output image (BMP file)
and here's my code :
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#define MAX_BRIGHTNESS 255
// C99 doesn't define M_PI (GNU-C99 does)
#define M_PI 3.14159265358979323846264338327
/*
* Loading part taken from
* http://www.vbforums.com/showthread.php?t=261522
* BMP info:
* http://en.wikipedia.org/wiki/BMP_file_format
*
* Note: the magic number has been removed from the bmpfile_header_t
* structure since it causes alignment problems
* bmpfile_magic_t should be written/read first
* followed by the
* bmpfile_header_t
* [this avoids compiler-specific alignment pragmas etc.]
*/
typedef struct {
uint8_t magic[2];
} bmpfile_magic_t;
typedef struct {
uint32_t filesz;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
} bmpfile_header_t;
typedef struct {
uint32_t header_sz;
int32_t width;
int32_t height;
uint16_t nplanes;
uint16_t bitspp;
uint32_t compress_type;
uint32_t bmp_bytesz;
int32_t hres;
int32_t vres;
uint32_t ncolors;
uint32_t nimpcolors;
} bitmap_info_header_t;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t nothing;
} rgb_t;
// Use short int instead `unsigned char' so that we can
// store negative values.
typedef short int pixel_t;
pixel_t *load_bmp(const char *filename,
bitmap_info_header_t *bitmapInfoHeader)
{
FILE *filePtr = fopen(filename, "rb");
if (filePtr == NULL) {
perror("fopen()");
return NULL;
}
bmpfile_magic_t mag;
if (fread(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// verify that this is a bmp file by check bitmap id
// warning: dereferencing type-punned pointer will break
// strict-aliasing rules [-Wstrict-aliasing]
if (*((uint16_t*)mag.magic) != 0x4D42) {
fprintf(stderr, "Not a BMP file: magic=%c%c\n",
mag.magic[0], mag.magic[1]);
fclose(filePtr);
return NULL;
}
bmpfile_header_t bitmapFileHeader; // our bitmap file header
// read the bitmap file header
if (fread(&bitmapFileHeader, sizeof(bmpfile_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// read the bitmap info header
if (fread(bitmapInfoHeader, sizeof(bitmap_info_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
if (bitmapInfoHeader->compress_type != 0)
fprintf(stderr, "Warning, compression is not supported.\n");
// move file point to the beginning of bitmap data
if (fseek(filePtr, bitmapFileHeader.bmp_offset, SEEK_SET)) {
fclose(filePtr);
return NULL;
}
// allocate enough memory for the bitmap image data
pixel_t *bitmapImage = malloc(bitmapInfoHeader->bmp_bytesz *
sizeof(pixel_t));
// verify memory allocation
if (bitmapImage == NULL) {
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
size_t pad, count=0;
unsigned char c;
pad = 4*ceil(bitmapInfoHeader->bitspp*bitmapInfoHeader->width/32.) - bitmapInfoHeader->width;
for(size_t i=0; i<bitmapInfoHeader->height; i++){
for(size_t j=0; j<bitmapInfoHeader->width; j++){
if (fread(&c, sizeof(unsigned char), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
bitmapImage[count++] = (pixel_t) c;
}
fseek(filePtr, pad, SEEK_CUR);
}
// If we were using unsigned char as pixel_t, then:
// fread(bitmapImage, 1, bitmapInfoHeader->bmp_bytesz, filePtr);
// close file and return bitmap image data
fclose(filePtr);
return bitmapImage;
}
// Return: true on error.
bool save_bmp(const char *filename, const bitmap_info_header_t *bmp_ih,
const pixel_t *data)
{
FILE* filePtr = fopen(filename, "wb");
if (filePtr == NULL)
return true;
bmpfile_magic_t mag = {{0x42, 0x4d}};
if (fwrite(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
const uint32_t offset = sizeof(bmpfile_magic_t) +
sizeof(bmpfile_header_t) +
sizeof(bitmap_info_header_t) +
((1U << bmp_ih->bitspp) * 4);
const bmpfile_header_t bmp_fh = {
.filesz = offset + bmp_ih->bmp_bytesz,
.creator1 = 0,
.creator2 = 0,
.bmp_offset = offset
};
if (fwrite(&bmp_fh, sizeof(bmpfile_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
if (fwrite(bmp_ih, sizeof(bitmap_info_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
// Palette
for (size_t i = 0; i < (1U << bmp_ih->bitspp); i++) {
const rgb_t color = {(uint8_t)i, (uint8_t)i, (uint8_t)i};
if (fwrite(&color, sizeof(rgb_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
// We use int instead of uchar, so we can't write img
// in 1 call any more.
// fwrite(data, 1, bmp_ih->bmp_bytesz, filePtr);
// Padding: http://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
size_t pad = 4*ceil(bmp_ih->bitspp*bmp_ih->width/32.) - bmp_ih->width;
unsigned char c;
for(size_t i=0; i < bmp_ih->height; i++) {
for(size_t j=0; j < bmp_ih->width; j++) {
c = (unsigned char) data[j + bmp_ih->width*i];
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
c = 0;
for(size_t j=0; j<pad; j++)
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
fclose(filePtr);
return false;
}
// if normalize is true, map pixels to range 0..MAX_BRIGHTNESS
void convolution(const pixel_t *in, pixel_t *out, const float *kernel,
const int nx, const int ny, const int kn,
const bool normalize)
{
assert(kn % 2 == 1);
assert(nx > kn && ny > kn);
const int khalf = kn / 2;
float min = FLT_MAX, max = -FLT_MAX;
if (normalize)
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (pixel < min)
min = pixel;
if (pixel > max)
max = pixel;
}
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (normalize)
pixel = MAX_BRIGHTNESS * (pixel - min) / (max - min);
out[n * nx + m] = (pixel_t)pixel;
}
}
/*
* gaussianFilter:
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
* determine size of kernel (odd #)
* 0.0 <= sigma < 0.5 : 3
* 0.5 <= sigma < 1.0 : 5
* 1.0 <= sigma < 1.5 : 7
* 1.5 <= sigma < 2.0 : 9
* 2.0 <= sigma < 2.5 : 11
* 2.5 <= sigma < 3.0 : 13 ...
* kernelSize = 2 * int(2*sigma) + 3;
*/
void gaussian_filter(const pixel_t *in, pixel_t *out,
const int nx, const int ny, const float sigma)
{
const int n = 2 * (int)(2 * sigma) + 3;
const float mean = (float)floor(n / 2.0);
float kernel[n * n]; // variable length array
fprintf(stderr, "gaussian_filter: kernel size %d, sigma=%g\n",
n, sigma);
size_t c = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
kernel[c] = exp(-0.5 * (pow((i - mean) / sigma, 2.0) +
pow((j - mean) / sigma, 2.0)))
/ (2 * M_PI * sigma * sigma);
c++;
}
convolution(in, out, kernel, nx, ny, n, true);
}
/*
* Links:
* http://en.wikipedia.org/wiki/Canny_edge_detector
* http://www.tomgibara.com/computer-vision/CannyEdgeDetector.java
* http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
*
* Note: T1 and T2 are lower and upper thresholds.
*/
pixel_t *canny_edge_detection(const pixel_t *in,
const bitmap_info_header_t *bmp_ih,
const int tmin, const int tmax,
const float sigma)
{
const int nx = bmp_ih->width;
const int ny = bmp_ih->height;
pixel_t *G = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gx = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gy = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *nms = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *out = malloc(bmp_ih->bmp_bytesz * sizeof(pixel_t));
if (G == NULL || after_Gx == NULL || after_Gy == NULL ||
nms == NULL || out == NULL) {
fprintf(stderr, "canny_edge_detection:"
" Failed memory allocation(s).\n");
exit(1);
}
gaussian_filter(in, out, nx, ny, sigma);
const float Gx[] = {-1, 0, 1,
-2, 0, 2,
-1, 0, 1};
convolution(out, after_Gx, Gx, nx, ny, 3, false);
const float Gy[] = { 1, 2, 1,
0, 0, 0,
-1,-2,-1};
convolution(out, after_Gy, Gy, nx, ny, 3, false);
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
// G[c] = abs(after_Gx[c]) + abs(after_Gy[c]);
G[c] = (pixel_t)hypot(after_Gx[c], after_Gy[c]);
}
// Non-maximum suppression, straightforward implementation.
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
const int nn = c - nx;
const int ss = c + nx;
const int ww = c + 1;
const int ee = c - 1;
const int nw = nn + 1;
const int ne = nn - 1;
const int sw = ss + 1;
const int se = ss - 1;
const float dir = (float)(fmod(atan2(after_Gy[c],
after_Gx[c]) + M_PI,
M_PI) / M_PI) * 8;
if (((dir <= 1 || dir > 7) && G[c] > G[ee] &&
G[c] > G[ww]) || // 0 deg
((dir > 1 && dir <= 3) && G[c] > G[nw] &&
G[c] > G[se]) || // 45 deg
((dir > 3 && dir <= 5) && G[c] > G[nn] &&
G[c] > G[ss]) || // 90 deg
((dir > 5 && dir <= 7) && G[c] > G[ne] &&
G[c] > G[sw])) // 135 deg
nms[c] = G[c];
else
nms[c] = 0;
}
// Reuse array
// used as a stack. nx*ny/2 elements should be enough.
int *edges = (int*) after_Gy;
memset(out, 0, sizeof(pixel_t) * nx * ny);
memset(edges, 0, sizeof(pixel_t) * nx * ny);
// Tracing edges with hysteresis . Non-recursive implementation.
size_t c = 1;
for (int j = 1; j < ny - 1; j++)
for (int i = 1; i < nx - 1; i++) {
if (nms[c] >= tmax && out[c] == 0) { // trace edges
out[c] = MAX_BRIGHTNESS;
int nedges = 1;
edges[0] = c;
do {
nedges--;
const int t = edges[nedges];
int nbs[8]; // neighbours
nbs[0] = t - nx; // nn
nbs[1] = t + nx; // ss
nbs[2] = t + 1; // ww
nbs[3] = t - 1; // ee
nbs[4] = nbs[0] + 1; // nw
nbs[5] = nbs[0] - 1; // ne
nbs[6] = nbs[1] + 1; // sw
nbs[7] = nbs[1] - 1; // se
for (int k = 0; k < 8; k++)
if (nms[nbs[k]] >= tmin && out[nbs[k]] == 0) {
out[nbs[k]] = MAX_BRIGHTNESS;
edges[nedges] = nbs[k];
nedges++;
}
} while (nedges > 0);
}
c++;
}
free(after_Gx);
free(after_Gy);
free(G);
free(nms);
return out;
}
int main(const int argc, const char ** const argv)
{
if (argc < 2) {
printf("Usage: %s image.bmp\n", argv[0]);
return 1;
}
static bitmap_info_header_t ih;
const pixel_t *in_bitmap_data = load_bmp(argv[1], &ih);
if (in_bitmap_data == NULL) {
fprintf(stderr, "main: BMP image not loaded.\n");
return 1;
}
printf("Info: %d x %d x %d\n", ih.width, ih.height, ih.bitspp);
const pixel_t *out_bitmap_data =
canny_edge_detection(in_bitmap_data, &ih, 45, 50, 1.0f);
if (out_bitmap_data == NULL) {
fprintf(stderr, "main: failed canny_edge_detection.\n");
return 1;
}
if (save_bmp("out.bmp", &ih, out_bitmap_data)) {
fprintf(stderr, "main: BMP image not saved.\n");
return 1;
}
free((pixel_t*)in_bitmap_data);
free((pixel_t*)out_bitmap_data);
return 0;
}
This isn't really an answer, but I wanted to post the image I obtained from the code.
I took two actions on the .jpg posted a) reduce to 256 colours, b) save as 8-bit .bmp, done with an image editor.
Then after running the code I converted the 8-bit .bmp output to .png to post here.
I only changed one thing for MSVC, the VLA
//float kernel[n * n]; // variable length array
float *kernel = malloc(n * n * sizeof (float));
with free(kernel) at the end of the function. Although there were still several compiler warnings, they didn't seem to be material here, but it's still worth fixing them.

As a result of processing arrays -nan(ind)

I am writing a program that creates arrays of a given length and manipulates them. You cannot use other libraries.
First, an array M1 of length N is formed, after which an array M2 of length N is formed/2.
In the M1 array, the division by Pi operation is applied to each element, followed by elevation to the third power.
Then, in the M2 array, each element is alternately added to the previous one, and the tangent modulus operation is applied to the result of addition.
After that, exponentiation is applied to all elements of the M1 and M2 array with the same indexes and the resulting array is sorted by dwarf sorting.
And at the end, the sum of the sines of the elements of the M2 array is calculated, which, when divided by the minimum non-zero element of the M2 array, give an even number.
The problem is that the result X gives is -nan(ind). I can't figure out exactly where the error is.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
const int A = 441;
const double PI = 3.1415926535897931159979635;
inline void dwarf_sort(double* array, int size) {
size_t i = 1;
while (i < size) {
if (i == 0) {
i = 1;
}
if (array[i - 1] <= array[i]) {
++i;
}
else
{
long tmp = array[i];
array[i] = array[i - 1];
array[i - 1] = tmp;
--i;
}
}
}
inline double reduce(double* array, int size) {
size_t i;
double min = RAND_MAX, sum = 0;
for (i = 0; i < size; ++i) {
if (array[i] < min && array[i] != 0) {
min = array[i];
}
}
for (i = 0; i < size; ++i) {
if ((int)(array[i] / min) % 2 == 0) {
sum += sin(array[i]);
}
}
return sum;
}
int main(int argc, char* argv[])
{
int i, N, j;
double* M1 = NULL, * M2 = NULL, * M2_copy = NULL;
double X;
unsigned int seed = 0;
N = atoi(argv[1]); /* N равен первому параметру командной строки */
M1 = malloc(N * sizeof(double));
M2 = malloc(N / 2 * sizeof(double));
M2_copy = malloc(N / 2 * sizeof(double));
for (i = 0; i < 100; i++)
{
seed = i;
srand(i);
/*generate*/
for (j = 0; j < N; ++j) {
M1[j] = (rand_r(&seed) % A) + 1;
}
for (j = 0; j < N / 2; ++j) {
M2[j] = (rand_r(&seed) % (10 * A)) + 1;
}
/*map*/
for (j = 0; j < N; ++j)
{
M1[j] = pow(M1[j] / PI, 3);
}
for (j = 0; j < N / 2; ++j) {
M2_copy[j] = M2[j];
}
M2[0] = fabs(tan(M2_copy[0]));
for (j = 0; j < N / 2; ++j) {
M2[j] = fabs(tan(M2[j] + M2_copy[j]));
}
/*merge*/
for (j = 0; j < N / 2; ++j) {
M2[j] = pow(M1[j], M2[j]);
}
/*sort*/
dwarf_sort(M2, N / 2);
/*sort*/
X = reduce(M2, N / 2);
}
printf("\nN=%d.\n", N);
printf("X=%f\n", X);
return 0;
}
Knowledgeable people, does anyone see where my mistake is? I think I'm putting the wrong data types to the variables, but I still can't solve the problem.
Replace the /* merge */ part with this:
/*merge*/
for (j = 0; j < N / 2; ++j) {
printf("%f %f ", M1[j], M2[j]);
M2[j] = pow(M1[j], M2[j]);
printf("%f\n", M2[j]);
}
This will print the values and the results of the pow operation. You'll see that some of these values are huge resulting in an capacity overflow of double.
Something like pow(593419.97, 31.80) will not end well.

I am trying to improve the performance speed of my cross-correlation algorithm. What things can I do to make my C code run faster?

I created a cross-correlation algorithm, and I am trying to maximize its performance by reducing the time it takes for it to run. First of all, I reduced the number of function calls within the "crossCorrelationV2" function. Second, I created several macros at the top of the program for constants. Third, I reduced the number of loops that are inside the "crossCorrelationV2" function. The code that you see is the most recent code that I have.
Are there any other methods I can use to try and reduce the processing time of my code?
Let's assume that I am only focused on the functions "crossCorrelationV2" and "createAnalyzingWave".
I would be glad for any advice, whether in general about programming or pertaining to those two specific functions; I am a beginner programmer. Thanks.
#include <stdio.h>
#include <stdlib.h>
#define ARRAYSIZE 4096
#define PULSESNUMBER 16
#define DATAFREQ 1300
// Print the contents of the array onto the console.
void printArray(double array[], int size){
int k;
for (k = 0; k < size; k++){
printf("%lf ", array[k]);
}
printf("\n");
}
// Creates analyzing square wave. This square wave has unity (1) magnitude.
// The number of high values in each period is determined by high values = (analyzingT/2) / time increment
void createAnalyzingWave(double analyzingFreq, double wave[]){
int highValues = (1 / analyzingFreq) * 0.5 / ((PULSESNUMBER * (1 / DATAFREQ) / ARRAYSIZE));
int counter = 0;
int p;
for(p = 1; p <= ARRAYSIZE; p++){
if ((counter % 2) == 0){
wave[p - 1] = 1;
} else{
wave[p - 1] = 0;
}
if (p % highValues == 0){
counter++;
}
}
}
// Creates data square wave (for testing purposes, for the real implementation actual ADC data will be used). This
// square wave has unity magnitude.
// The number of high values in each period is determined by high values = array size / (2 * number of pulses)
void createDataWave(double wave[]){
int highValues = ARRAYSIZE / (2 * PULSESNUMBER);
int counter = 0;
int p;
for(p = 0; p < ARRAYSIZE; p++){
if ((counter % 2) == 0){
wave[p] = 1;
} else{
wave[p] = 0;
}
if ((p + 1) % highValues == 0){
counter++;
}
}
}
// Finds the average of all the values inside an array
double arrayAverage(double array[], int size){
int i;
double sum = 0;
// Same thing as for(i = 0; i < arraySize; i++)
for(i = size; i--; ){
sum = array[i] + sum;
}
return sum / size;
}
// Cross-Correlation algorithm
double crossCorrelationV2(double dataWave[], double analyzingWave[]){
int bigArraySize = (2 * ARRAYSIZE) - 1;
// Expand analyzing array into array of size 2arraySize-1
int lastArrayIndex = ARRAYSIZE - 1;
int lastBigArrayIndex = 2 * ARRAYSIZE - 2; //bigArraySize - 1; //2 * arraySize - 2;
double bigAnalyzingArray[bigArraySize];
int i;
int b;
// Set first few elements of the array equal to analyzingWave
// Set remainder of big analyzing array to 0
for(i = 0; i < ARRAYSIZE; i++){
bigAnalyzingArray[i] = analyzingWave[i];
bigAnalyzingArray[i + ARRAYSIZE] = 0;
}
double maxCorrelationValue = 0;
double currentCorrelationValue;
// "Beginning" of correlation algorithm proper
for(i = 0; i < bigArraySize; i++){
currentCorrelationValue = 0;
for(b = lastBigArrayIndex; b > 0; b--){
if (b >= lastArrayIndex){
currentCorrelationValue = dataWave[b - lastBigArrayIndex / 2] * bigAnalyzingArray[b] + currentCorrelationValue;
}
bigAnalyzingArray[b] = bigAnalyzingArray[b - 1];
}
bigAnalyzingArray[0] = 0;
if (currentCorrelationValue > maxCorrelationValue){
maxCorrelationValue = currentCorrelationValue;
}
}
return maxCorrelationValue;
}
int main(){
int samplesNumber = 25;
double analyzingFreq = 1300;
double analyzingWave[ARRAYSIZE];
double dataWave[ARRAYSIZE];
createAnalyzingWave(analyzingFreq, analyzingWave);
//createDataWave(arraySize, pulsesNumber, dataWave);
double maximumCorrelationArray[samplesNumber];
int i;
for(i = 0; i < samplesNumber; i++){
createDataWave(dataWave);
maximumCorrelationArray[i] = crossCorrelationV2(dataWave, analyzingWave);
}
printf("Average of the array values: %lf\n", arrayAverage(maximumCorrelationArray, samplesNumber));
return 0;
}
The first point is that you are explicitly shifting the analizingData array, this way you are required twice as much memory and moving the items is about 50% of your time. In a test here using crossCorrelationV2 takes 4.1 seconds, with the implementation crossCorrelationV3 it runs in ~2.0 seconds.
The next thing is that you are spending time multiplying by zero on the padded array, removing that, and also removing the padding, and simplifying the indices we end with crossCorrelationV4 that makes the program to run in ~1.0 second.
// Cross-Correlation algorithm
double crossCorrelationV3(double dataWave[], double analyzingWave[]){
int bigArraySize = (2 * ARRAYSIZE) - 1;
// Expand analyzing array into array of size 2arraySize-1
int lastArrayIndex = ARRAYSIZE - 1;
int lastBigArrayIndex = 2 * ARRAYSIZE - 2; //bigArraySize - 1; //2 * arraySize - 2;
double bigAnalyzingArray[bigArraySize];
int i;
int b;
// Set first few elements of the array equal to analyzingWave
// Set remainder of big analyzing array to 0
for(i = 0; i < ARRAYSIZE; i++){
bigAnalyzingArray[i] = analyzingWave[i];
bigAnalyzingArray[i + ARRAYSIZE] = 0;
}
double maxCorrelationValue = 0;
double currentCorrelationValue;
// "Beginning" of correlation algorithm proper
for(i = 0; i < bigArraySize; i++){
currentCorrelationValue = 0;
// Instead of checking if b >= lastArrayIndex inside the loop I use it as
// a stopping condition.
for(b = lastBigArrayIndex; b >= lastArrayIndex; b--){
// instead of shifting bitAnalizing[b] = bigAnalyzingArray[b-1] every iteration
// I simply use bigAnalizingArray[b-i]
currentCorrelationValue = dataWave[b - lastBigArrayIndex / 2] * bigAnalyzingArray[b - i] + currentCorrelationValue;
}
bigAnalyzingArray[0] = 0;
if (currentCorrelationValue > maxCorrelationValue){
maxCorrelationValue = currentCorrelationValue;
}
}
return maxCorrelationValue;
}
// Cross-Correlation algorithm
double crossCorrelationV4(double dataWave[], double analyzingWave[]){
int bigArraySize = (2 * ARRAYSIZE) - 1;
// Expand analyzing array into array of size 2arraySize-1
int lastArrayIndex = ARRAYSIZE - 1;
int lastBigArrayIndex = 2 * ARRAYSIZE - 2; //bigArraySize - 1; //2 * arraySize - 2;
// I will not allocate the bigAnalizingArray here
// double bigAnalyzingArray[bigArraySize];
int i;
int b;
// I will not copy the analizingWave to bigAnalyzingArray
// for(i = 0; i < ARRAYSIZE; i++){
// bigAnalyzingArray[i] = analyzingWave[i];
// bigAnalyzingArray[i + ARRAYSIZE] = 0;
// }
double maxCorrelationValue = 0;
double currentCorrelationValue;
// Compute the correlation by symmetric paris
// the idea here is to simplify the indices of the inner loops since
// they are computed more times.
for(i = 0; i < lastArrayIndex; i++){
currentCorrelationValue = 0;
for(b = lastArrayIndex - i; b >= 0; b--){
// instead of shifting bitAnalizing[b] = bigAnalyzingArray[b-1] every iteration
// I simply use bigAnalizingArray[b-i]
currentCorrelationValue += dataWave[b] * analyzingWave[b + i];
}
if (currentCorrelationValue > maxCorrelationValue){
maxCorrelationValue = currentCorrelationValue;
}
if(i != 0){
currentCorrelationValue = 0;
// Correlate shifting to the other side
for(b = lastArrayIndex - i; b >= 0; b--){
// instead of shifting bitAnalizing[b] = bigAnalyzingArray[b-1] every iteration
// I simply use bigAnalizingArray[b-i]
currentCorrelationValue += dataWave[b + i] * analyzingWave[b];
}
if (currentCorrelationValue > maxCorrelationValue){
maxCorrelationValue = currentCorrelationValue;
}
}
}
return maxCorrelationValue;
}
If you want more optimization you can unroll some iterations of the loop and enable some compiler optimizations like vector extension.

Scaling up an image using nearest-neighbor

I have been trying to make my program scale up an image. I had some problem to allocate new space for my scaled image, but I think it is fixed. The problem I am having is that the program crashes when I am trying to send back my image from my temporary memory holder.
The loaded image is placed in my struct Image. The pixels are placed in
img->pixels, the height in img->height and the width in img->width. But I have no idea why the program crashes when I transfer the pixels from my tmp2 struct to my img struct while it does not crash when I do the opposite. Here is the code:
void makeBigger(Image *img, int scale) {
Image *tmp2;
tmp2 = (Image*)malloc(sizeof(Image));
tmp2->height = img->height*scale;
tmp2->width = img->width*scale;
tmp2->pixels = (Pixel**)malloc(sizeof(Pixel*)*tmp2->height);
for (unsigned int i = 0; i < img->height; i++)
{
tmp2->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*tmp2->width);
for (unsigned int j = 0; j < img->width; j++)
{
tmp2->pixels[i][j] = img->pixels[i][j];
}
}
free(img->pixels);
//scaling up the struct's height and width
img->height *= scale;
img->width *= scale;
img->pixels = (Pixel**)malloc(sizeof(Pixel*)*img->height);
for (unsigned int i = 0; i < tmp2->height; i++)
{
img->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*img->width);
for (unsigned int j = 0; j < tmp2->width; j++)
{
img->pixels[i][j] = tmp2->pixels[i+i/2][j+j/2];
}
}
}
I would be glad if you have any idea of how to make the nearest-neighbor method to work.
EDIT: I am trying to crop the inner rectangle so I can scale it up (zoom).
Image *tmp = (Image*)malloc(sizeof(Image));
tmp->height = img->height / 2;
tmp->width = img->width / 2;
tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height);
for (unsigned i = img->height / 4 - 1; i < img->height - img->height / 4; i++) {
tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width);
for (unsigned j = img->width / 4; j < img->width - img->width / 4; j++) {
tmp->pixels[i][j] = img->pixels[i][j];
}
}
for (unsigned i = 0; i < img->height; i++) {
free(img->pixels[i]);
}
free(img->pixels);
img->height = tmp->height;
img->width = tmp->width;
img->pixels = tmp->pixels;
free(tmp);
I see that you're overcomplicating things (walking over the image twice for example).Here's the code (I am posting the whole program - I made assumptions about Pixel and Image that might not match what you have), but if you copy / paste makeBigger it should work in your code OOTB:
code00.c:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint32_t Pixel;
typedef struct {
uint32_t width, height;
Pixel **pixels;
} Image;
void makeBigger(Image *img, int scale)
{
uint32_t i = 0, j = 0;
Image *tmp = (Image*)malloc(sizeof(Image));
tmp->height = img->height * scale;
tmp->width = img->width * scale;
tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height);
for (i = 0; i < tmp->height; i++) {
tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width);
for (j = 0; j < tmp->width; j++) {
tmp->pixels[i][j] = img->pixels[i / scale][j / scale];
}
}
for (i = 0; i < img->height; i++)
free(img->pixels[i]);
free(img->pixels);
img->width = tmp->width;
img->height = tmp->height;
img->pixels = tmp->pixels;
free(tmp);
}
void printImage(Image *img)
{
printf("Width: %d, Height: %d\n", img->width, img->height);
for (uint32_t i = 0; i < img->height; i++) {
for (uint32_t j = 0; j < img->width; j++)
printf("%3d", img->pixels[i][j]);
printf("\n");
}
printf("\n");
}
int main()
{
uint32_t i = 0, j = 0, k = 1;
Image img;
// Initialize the image
img.height = 2;
img.width = 3;
img.pixels = (Pixel**)malloc(sizeof(Pixel*) * img.height);
for (i = 0; i < img.height; i++) {
img.pixels[i] = (Pixel*)malloc(sizeof(Pixel) * img.width);
for (j = 0; j < img.width; j++)
img.pixels[i][j] = k++;
}
printImage(&img);
makeBigger(&img, 2);
printImage(&img);
// Destroy the image
for (i = 0; i < img.height; i++)
free(img.pixels[i]);
free(img.pixels);
printf("\nDone.\n");
return 0;
}
Notes (makeBigger related - designed to replace the content of the image given as argument):
Construct a temporary image that will be the enlarged one
Only traverse the temporary image once (populate its pixels as we allocate them); to maintain scaling to the original image and make sure that the appropriate pixel is "copied" into the new one, simply divide the indexes by the scaling factor: tmp->pixels[i][j] = img->pixels[i / scale][j / scale]
Deallocate the original image content: since each pixel row is malloced, it should also be freed (free(img->pixels); alone will yield memory leaks)
Store the temporary image content (into the original one) and then deallocate it
Output:
[cfati#cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q041861274]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> ls
code00.c
[064bit prompt]> gcc -o code00.exe code00.c
[064bit prompt]> ./code00.exe
Width: 3, Height: 2
1 2 3
4 5 6
Width: 6, Height: 4
1 1 2 2 3 3
1 1 2 2 3 3
4 4 5 5 6 6
4 4 5 5 6 6
Done.

Resources