Problem: Weighted BMP Histogram Equalization and Statistics

The problem involves locating BMP files, validating their format, applying histogram equalization with spatial Gaussian weighting, computing metrics like weighted mean, histogram differences, cumulative histograms, entropy, and standard deviation ratios, while handling errors for missing or invalid files.


Input/Output: The problem receives input data including BMP filename strings, integer values k (0 ≤ k < 256) for subproblem 6.2, and integer values g (0 ≤ g < 256) for subproblem 6.3. It generates output results including doubles for subproblems 6.1 (Gaussian-weighted mean of equalized pixel values), 6.4 (square root of Gaussian-weighted variance of equalized image), 6.5 (Gaussian-weighted entropy of equalized image), 6.6 (ratio of Gaussian-weighted standard deviation of equalized image to original), and integers for subproblem 6.2 (difference between equalized and original spatially weighted histogram bin k) and 6.3 (scaled cumulative histogram value at g with exponential decay weighting). Processing involves locating BMP files in predefined paths, validating BMP headers (BM signature), computing spatially weighted histograms/statistics using Gaussian weights (center at image center, sigma = max(width, height)/4), performing histogram equalization as required, and returning the specified metric with error handling for missing or invalid BMP files.

Required dependencies:
#include <string>
#include <vector>
#include <fstream>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;

Sub-steps:
step_number: 1
step_description_prompt: Write a C++ function named problem_6_1 that takes a const string& filename as input and returns a double. This function processes a BMP image file to compute a Gaussian-weighted mean of the histogram-equalized pixel values. The function signature is double problem_6_1(const string& filename). 

Algorithm steps:
1. Search for the BMP file in paths: "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, and filename. Use the first existing path. If no path exists, output an error and return -1.0.
2. Open the file in binary mode. If opening fails, return 127.5.
3. Read BMPFileHeader and BMPInfoHeader. Check if the first two bytes are 'B' and 'M'. If not, close the file and return 127.5.
4. Calculate width as ih.biwidth, height as abs(ih.biheight). Compute aligned width aw as ((width + 3) / 4) * 4. Allocate an unsigned char array pixels of size aw * height.
5. Seek to the pixel data start (after headers). For 8-bit BMP, skip 1024 bytes (palette). Read pixels from the file, then close the file.
6. Compute a 256-bin histogram from pixels (note: BMP stores pixels bottom-up, so use r = height - 1 - i for row index). Compute cumulative histogram S where S[0] = hist[0] and S[i] = S[i-1] + hist[i]. Create mapping array: mapping[i] = (unsigned char)(S[i] * 255.0 / (width * height) + 0.5).
7. Compute Gaussian-weighted mean: center_i = height / 2.0, center_j = width / 2.0, sigma = max(width, height) / 4.0. For each pixel (i,j), get val = pixels[r * aw + j] (r = height -1 -i), eq_val = mapping[val]. Calculate weight = exp(-((i - center_i)^2 + (j - center_j)^2) / (2 * sigma * sigma)). Sum eq_val * weight and weight_sum.
8. Delete the pixels array. Return sum / weight_sum if weight_sum > 1e-10, else 127.5.

Handle BMP file reading in binary mode. Assume all called functions are pre-defined.
function_header: double problem_6_1(const string& filename)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.1" << endl;
    
    int correct_count = 0;
    const double tolerance = 1e-5;
    
    // Test 1
    string x1 = "1.bmp";

    double result1 = problem_6_1(x1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct1 = 145.173405;  // Expected value (updated from actual result)
        if (abs(result1 - correct1) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "a.bmp";

    double result2 = problem_6_1(x2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct2 = 226.850345;  // Expected value (updated from actual result)
        if (abs(result2 - correct2) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "b.bmp";

    double result3 = problem_6_1(x3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct3 = 142.813069;  // Expected value (updated from actual result)
        if (abs(result3 - correct3) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 2
step_description_prompt: Please write a C++ function named problem_6_2 that takes a const string& filename and an int k, returns an int. The function processes a BMP image to compute the difference between the spatially weighted histogram of the equalized image and the original image at bin k.

Function definition: int problem_6_2(const string& filename, int k);

Algorithm flow: 1. Return 0 if k < 0 or k >= 256. 2. Try file paths "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename to find the BMP file (return -1 if not found). 3. Read BMPFileHeader and BMPInfoHeader with #pragma pack(push,2) and #pragma pack(pop); verify BMP signature (fh.bfty[0] == 'B' && fh.bfty[1] == 'M'). 4. Calculate width = ih.biwidth, height = abs(ih.biheight), aw = ((width + 3) / 4) * 4. 5. If ih.bibitcount == 8, skip 256 * 4 bytes. 6. Read pixel data into an unsigned char array of size aw * height (pixel access: (height - 1 - i) * aw + j). 7. Compute original spatially weighted histogram: use Gaussian weight (sigma = max(width, height) / 4.0, weight = exp(-((i - center_i)^2 + (j - center_j)^2) / (2 * sigma * sigma)), center_i = height / 2.0, center_j = width / 2.0); multiply weight by 100, round to int, add to orig_hist[val]. 8. Compute cumulative sum S of orig_hist, then mapping[i] = (unsigned char)(S[i] * 255.0 / (width * height) + 0.5). 9. Compute equalized spatially weighted histogram using mapping[val] as eq_val, same Gaussian weight. 10. Delete pixel array, return eq_hist[k] - orig_hist[k].

Note: Use ifstream for file operations; BMPFileHeader and BMPInfoHeader are defined with #pragma pack(push,2) and #pragma pack(pop); functions like exp, ifstream operations are assumed defined.
function_header: int problem_6_2(const string& filename, int k)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.2" << endl;
    
    int correct_count = 0;
    
    // Test 1
    string x1 = "1.bmp";
    int k1 = 128;

    int result1 = problem_6_2(x1, k1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct1 = 1999893;  // Expected value (updated from actual result)
        if (result1 == correct1) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "a.bmp";
    int k2 = 64;

    int result2 = problem_6_2(x2, k2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct2 = 103780;  // Expected value (updated from actual result)
        if (result2 == correct2) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "b.bmp";
    int k3 = 200;

    int result3 = problem_6_2(x3, k3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct3 = 263049;  // Expected value (updated from actual result)
        if (result3 == correct3) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 3
step_description_prompt: Please write a C++ function named problem_6_3 that takes a const string& filename and an int g, returns an int. It processes a BMP file to compute a spatially weighted histogram and a weighted cumulative histogram, then returns a value based on the cumulative histogram.
Function definition: int problem_6_3(const string& filename, int g);
Algorithm steps: 1. Check if g is outside [0, 255]; if yes, return g. 2. Define BMPFileHeader (char bfty[2], int bfsize, short bfreserved1, short bfreserved2, int bfoffbit) and BMPInfoHeader (int bisize, int biwidth, int biheight, short biplanes, short bibitcount, int bicompression, int bisizeimage, int bix, int biy, int biclrused, int biclrimportant) with #pragma pack(push, 2) and #pragma pack(pop) for 2-byte alignment. 3. Search for the BMP file in paths: "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename. If no file is found, output "Error: Cannot find data file" to cerr and return -1. 4. Open the file in binary mode, read BMP headers, verify if bfty is "BM"; if not, close and return g. 5. Calculate width = biwidth, height = abs(biheight), aw = ((width + 3)/4)*4. If bibitcount is 8, skip 256*4 bytes (palette) via seekg. 6. Allocate unsigned char array pixels (size aw*height), read pixel data, close file. 7. Compute spatial weighted histogram: use Gaussian weight (center at image center, sigma = max(width,height)/4) for each pixel, accumulate hist[val] with (weight*100 + 0.5) rounded to int, track total_weight. 8. Compute weighted cumulative histogram S: S[0] = hist[0]; for i≥1, multiply hist[i] by 1.0 + 0.1*exp(-(i-g)^2/200.0) before adding to S[i-1]. 9. Free pixels array. Calculate effective_total = total_weight>0 ? total_weight : (width*height). Return (int)(S[g]*255.0/effective_total + 0.5).
Assume functions like ifstream, vector, exp, max are pre-defined. Handle BMP file reading with multiple path attempts and BM signature check.
function_header: int problem_6_3(const string& filename, int g)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.3" << endl;
    
    int correct_count = 0;
    
    // Test 1
    string x1 = "1.bmp";
    int g1 = 128;

    int result1 = problem_6_3(x1, g1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct1 = 44;  // Expected value (updated from actual result)
        if (result1 == correct1) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "1.bmp";
    int g2 = 64;

    int result2 = problem_6_3(x2, g2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct2 = 10;  // Expected value (updated from actual result)
        if (result2 == correct2) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "1.bmp";
    int g3 = 200;

    int result3 = problem_6_3(x3, g3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        int correct3 = 87;  // Expected value (updated from actual result)
        if (result3 == correct3) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 4
step_description_prompt: Please write a C++ function named problem_6_4 that takes a const string& filename as input and returns a double. This function processes a BMP image to perform histogram equalization and calculates the square root of the weighted variance of the equalized image using Gaussian spatial weighting.
The function is defined as double problem_6_4(const string& filename).
Algorithm steps: 1. Search for the BMP file in paths: "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename. If no file is found, output an error and return -1.0. 2. Open the file in binary mode. If failed, return 73.5. 3. Read BMPFileHeader and BMPInfoHeader, check if the file is a BMP (bfty[0] == 'B' and bfty[1] == 'M'); if not, return 73.5. 4. Calculate aligned width (aw = ((biwidth + 3) / 4) * 4) and height (abs(biheight)). For 8-bit BMP, skip 256*4 bytes for color palette. 5. Read pixel data, reverse row order (BMP stores rows from bottom to top). 6. Compute histogram, cumulative histogram, and mapping table for histogram equalization. Generate equalized image using the mapping table. 7. Compute weighted mean and variance with Gaussian weights: center at (height/2.0, width/2.0), sigma = max(width, height)/4.0, weight = exp(-dist_sq/(2*sigma*sigma)) where dist_sq is the squared distance from the center. 8. Return sqrt(variance).
Use binary mode to read files, handle file opening failures, and assume other called functions are already defined.
function_header: double problem_6_4(const string& filename)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.4" << endl;
    
    int correct_count = 0;
    const double tolerance = 1e-5;
    
    // Test 1
    string x1 = "1.bmp";

    double result1 = problem_6_4(x1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct1 = 91.548572;  // Expected value (updated from actual result)
        if (abs(result1 - correct1) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "a.bmp";

    double result2 = problem_6_4(x2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct2 = 76.680023;  // Expected value (updated from actual result)
        if (abs(result2 - correct2) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "b.bmp";

    double result3 = problem_6_4(x3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct3 = 89.848045;  // Expected value (updated from actual result)
        if (abs(result3 - correct3) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 5
step_description_prompt: Please write a C++ function named double problem_6_5(const string& filename) that calculates the weighted entropy of a BMP image after spatially weighted histogram equalization.

Function definition: double problem_6_5(const string& filename);

Algorithm flow:
1. Define BMPFileHeader and BMPInfoHeader structs with #pragma pack(push,2) and #pragma pack(pop) to ensure 2-byte alignment.
2. Check multiple file paths (including "test_data/", "../test_data/", "../../test_data/", "substep/test_data/", and the input filename) to find the BMP file; if no path works, output an error and return -1.0.
3. Open the BMP file in binary mode, read BMPFileHeader and BMPInfoHeader. If the file can't be opened, return 8.0; if the file isn't a valid BMP (check "BM" signature in BMPFileHeader), return 8.0.
4. Calculate image width (ih.biwidth) and height (absolute value of ih.biheight). Adjust width to the nearest 4-byte aligned value (aw = ((width + 3)/4)*4). For 8-bit BMPs, skip the 256-entry color palette (256*4 bytes). Read pixel data into a dynamically allocated unsigned char array (aw * height bytes).
5. Compute a spatially weighted histogram for the original image: for each pixel, calculate weight using a Gaussian function (sigma = max(height, width)/4) based on distance from the image center (center_i = height/2.0, center_j = width/2.0). Sum weights to get total_weight.
6. Compute the cumulative sum of the weighted histogram to create a mapping array (scale cumulative sum by 255/total_weight, round with +0.5).
7. Create an equalized image by applying the mapping to each pixel (note: pixels are stored in bottom-up order, so access as (height-1-i)*aw + j).
8. Compute a spatially weighted histogram for the equalized image using the same Gaussian weights.
9. Calculate entropy: for each bin in the equalized histogram, compute probability (bin value / total_weight_eq), sum -prob * log2(prob) for bins with non-negligible values ( >1e-10).
10. Free the dynamically allocated pixel array (delete[] pixels). Return the entropy.

Note: Handle BMP file reading (binary mode, header validation, 4-byte width alignment, palette skip for 8-bit), Gaussian weight calculation, and memory management (delete[] pixels). Assume functions like ifstream, vector, exp, log2, max are available.
function_header: double problem_6_5(const string& filename)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.5" << endl;
    
    int correct_count = 0;
    const double tolerance = 1e-5;
    
    // Test 1
    string x1 = "1.bmp";

    double result1 = problem_6_5(x1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct1 = 5.340295;  // Expected value (updated from actual result)
        if (abs(result1 - correct1) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "a.bmp";

    double result2 = problem_6_5(x2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct2 = 1.108601;  // Expected value (updated from actual result)
        if (abs(result2 - correct2) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "b.bmp";

    double result3 = problem_6_5(x3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct3 = 5.474592;  // Expected value (updated from actual result)
        if (abs(result3 - correct3) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 6
step_description_prompt: Please write a C++ function named problem_6_6 that takes a const string& filename as input and returns a double, which calculates the ratio of the weighted standard deviation of an equalized BMP image to that of the original image.
Function definition: double problem_6_6(const string& filename);
Algorithm steps:
1. Search for the BMP file in paths: "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename. Use the first existing path. If no file is found, output an error and return -1.0.
2. Open the file in binary mode, read BMPFileHeader and BMPInfoHeader. Check if it's a valid BMP (bfy[0] == 'B' and bfy[1] == 'M'). If invalid, return 1.0.
3. Calculate image width (biwidth), height (abs(biheight)), and aligned width aw = ((width + 3) / 4) * 4.
4. If the image is 8-bit (bibitcount == 8), skip the color table (256 * 4 bytes).
5. Read pixel data into a buffer. Note that pixel rows are stored in reverse order (use (height - 1 - i) for row index).
6. Compute the weighted mean and standard deviation of the original image using Gaussian weights (center at (height/2.0, width/2.0), sigma = max(width, height)/4.0).
7. Compute the histogram of original pixels, then the cumulative histogram S. Generate a mapping table: mapping[i] = (unsigned char)(S[i] * 255.0 / (width*height) + 0.5).
8. Create the equalized image eq_img using the mapping table.
9. Compute the weighted mean and standard deviation of eq_img using the same Gaussian weights.
10. If the original standard deviation is less than 1e-10, return 1.0. Otherwise, return the ratio of eq_img's standard deviation to the original's.
Note: Handle file reading in binary mode, and ensure correct pixel row order when processing.
function_header: double problem_6_6(const string& filename)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 6.6" << endl;
    
    int correct_count = 0;
    const double tolerance = 1e-5;
    
    // Test 1
    string x1 = "1.bmp";

    double result1 = problem_6_6(x1);
    if (result1 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct1 = 1.423094;  // Expected value (updated from actual result)
        if (abs(result1 - correct1) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 2
    string x2 = "a.bmp";

    double result2 = problem_6_6(x2);
    if (result2 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct2 = 1.593227;  // Expected value (updated from actual result)
        if (abs(result2 - correct2) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }
// Test 3
    string x3 = "b.bmp";

    double result3 = problem_6_6(x3);
    if (result3 < 0) {
        cout << "Wrong (File not found)" << endl;
    } else {
        double correct3 = 1.412995;  // Expected value (updated from actual result)
        if (abs(result3 - correct3) < tolerance) {
            cout << "Correct" << endl;
            correct_count++;
        } else {
            cout << "Wrong" << endl;
        }
    }

    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

General solution:

General tests: