Skip to main content

Overview

Provides utility functions for CPU detection, value clamping, min/max operations, and index reflection for boundary handling.

Functions

get_cpus_count

Returns the number of available CPU cores.
int get_cpus_count();
return
int
Number of CPU cores available on the system
Useful for determining optimal thread count for parallel operations. Typically used to create thread pools for image processing tasks.

Example

int num_threads = get_cpus_count();
printf("Using %d threads for processing\n", num_threads);

// Create thread pool based on CPU count
pthread_t *threads = malloc(num_threads * sizeof(pthread_t));

clamp

Clamps an integer value to a specified range.
int clamp(int value, int min, int max);
value
int
required
Value to clamp
min
int
required
Minimum allowed value
max
int
required
Maximum allowed value
return
int
Clamped value: min if value < min, max if value > max, otherwise value
Ensures the value stays within bounds [min, max]. Commonly used for pixel value clamping and boundary checking.

Example

int pixel_value = 300;
int clamped = clamp(pixel_value, 0, 255);
printf("%d\n", clamped); // Output: 255

int negative = clamp(-50, 0, 255);
printf("%d\n", negative); // Output: 0

int normal = clamp(128, 0, 255);
printf("%d\n", normal); // Output: 128

min

Returns the minimum of two integers.
int min(int a, int b);
a
int
required
First value
b
int
required
Second value
return
int
The smaller of a and b

Example

int width = min(image1.width, image2.width);
printf("Minimum width: %d\n", width);

// Limit processing to available data
int process_count = min(available_items, max_items);

max

Returns the maximum of two integers.
int max(int a, int b);
a
int
required
First value
b
int
required
Second value
return
int
The larger of a and b

Example

int height = max(image1.height, image2.height);
printf("Maximum height: %d\n", height);

// Ensure minimum buffer size
int buffer_size = max(required_size, 1024);

reflect_index

Reflects an index at image boundaries for border handling.
int reflect_index(int i, int n);
i
int
required
Index to reflect (can be negative or >= n)
n
int
required
Maximum valid index (typically image dimension)
return
int
Reflected index in valid range [0, n-1]
Used for reflective boundary handling in image operations. When accessing pixels outside image bounds, this function mirrors the index back into valid range.

Example

int width = 100;

// Negative indices reflect back
int idx1 = reflect_index(-1, width);
printf("%d\n", idx1); // Output: 1 (reflects off left edge)

int idx2 = reflect_index(-5, width);
printf("%d\n", idx2); // Output: 5

// Indices beyond bounds reflect back
int idx3 = reflect_index(100, width);
printf("%d\n", idx3); // Output: 98 (reflects off right edge)

int idx4 = reflect_index(105, width);
printf("%d\n", idx4); // Output: 93

// Valid indices pass through
int idx5 = reflect_index(50, width);
printf("%d\n", idx5); // Output: 50

Practical Usage: Reflective Border Access

// Access pixel with reflective boundary handling
unsigned char get_pixel_safe(Image *img, int x, int y, int channel) {
    // Reflect coordinates if out of bounds
    int safe_x = reflect_index(x, img->width);
    int safe_y = reflect_index(y, img->height);
    
    // Clamp channel to valid range
    int safe_c = clamp(channel, 0, img->channels - 1);
    
    // Calculate index and return pixel
    int idx = (safe_y * img->width + safe_x) * img->channels + safe_c;
    return img->data[idx];
}

// Use in filtering operations
void apply_filter(Image *img, float kernel[3][3]) {
    Image output = create_empty_image(img->width, img->height, img->channels);
    
    for (int y = 0; y < img->height; y++) {
        for (int x = 0; x < img->width; x++) {
            for (int c = 0; c < img->channels; c++) {
                float sum = 0.0f;
                
                // Apply 3x3 kernel with reflective boundaries
                for (int ky = -1; ky <= 1; ky++) {
                    for (int kx = -1; kx <= 1; kx++) {
                        unsigned char pixel = get_pixel_safe(img, 
                                                            x + kx, 
                                                            y + ky, 
                                                            c);
                        sum += pixel * kernel[ky + 1][kx + 1];
                    }
                }
                
                int idx = (y * img->width + x) * img->channels + c;
                output.data[idx] = (unsigned char)clamp((int)sum, 0, 255);
            }
        }
    }
    
    // Use output...
    destroy_image(&output);
}

Complete Usage Example

#include "utils.h"
#include "image_operations.h"
#include <pthread.h>

typedef struct {
    Image *img;
    int start_row;
    int end_row;
} ThreadData;

void *process_rows(void *arg) {
    ThreadData *data = (ThreadData *)arg;
    
    for (int y = data->start_row; y < data->end_row; y++) {
        for (int x = 0; x < data->img->width; x++) {
            for (int c = 0; c < data->img->channels; c++) {
                int idx = (y * data->img->width + x) * data->img->channels + c;
                
                // Example: brighten and clamp
                int value = data->img->data[idx] + 50;
                data->img->data[idx] = clamp(value, 0, 255);
            }
        }
    }
    
    return NULL;
}

void parallel_brighten(Image *img) {
    int num_threads = get_cpus_count();
    pthread_t *threads = malloc(num_threads * sizeof(pthread_t));
    ThreadData *thread_data = malloc(num_threads * sizeof(ThreadData));
    
    int rows_per_thread = img->height / num_threads;
    
    // Create threads
    for (int i = 0; i < num_threads; i++) {
        thread_data[i].img = img;
        thread_data[i].start_row = i * rows_per_thread;
        thread_data[i].end_row = (i == num_threads - 1) 
                                  ? img->height 
                                  : (i + 1) * rows_per_thread;
        
        pthread_create(&threads[i], NULL, process_rows, &thread_data[i]);
    }
    
    // Wait for completion
    for (int i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }
    
    free(threads);
    free(thread_data);
}

Build docs developers (and LLMs) love