Problem: BMP Weighted Histogram Analysis Functions

The problem focuses on BMP image processing—locating files, reading headers, computing histograms (with Gaussian weighting), and performing tasks like gray-level count retrieval, peak detection, weighted cumulative sum calculation, and result normalization—to create functions for histogram-based image analysis.


Input/Output: The problem takes, for four subproblems, a string filename (identifying a BMP file) and parameters: subproblem 2.1 uses an integer gray_level (0–255); subproblems 2.3 and 2.4 use an integer k (0–255). BMP files are located via predefined paths (e.g., "test_data/", "../test_data/"). It computes histograms (with Gaussian spatial weighting for 2.1). For 2.1, it returns an integer (Gaussian-weighted histogram count for gray_level, -1 if file not found, 0 if gray_level is invalid). For 2.2, it returns an integer (multi-Gaussian weighted peak level in the histogram). For 2.3, it returns a long long (weighted cumulative sum of histogram bins from 0 to min(k,255), -1 if file not found). For 2.4, it returns a double (normalized weighted cumulative sum calculated as cumulative sum * 255 / total pixels, -1.0 if file not found).

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

Sub-steps:
step_number: 1
step_description_prompt: Please write a C++ function named problem_2_1 that takes a const string& filename and an int gray_level as parameters, which calculates the spatially weighted histogram value of a specific gray level in a BMP image.
The function signature is int problem_2_1(const string& filename, int gray_level).
First, define BMPFileHeader (contains char bfty[2], int bfsize, short bfreserved1, short bfreserved2, int bfoffbit) and BMPInfoHeader (contains 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 alignment.
Check multiple possible paths for the file: "test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename. If no path is valid, output "Error: Cannot find data file" to cerr and return -1.
Read BMP headers. If the file is a valid BMP (bfty[0] == 'B' and bfty[1] == 'M'), get width as biwidth and height as absolute biheight. For 8-bit BMP, skip 1024 bytes (palette). Calculate aligned width as ((width + 3) / 4) * 4, then read pixel data into a buffer.
Compute the spatially weighted histogram: iterate over each pixel, reverse rows (since BMP stores pixels from bottom to top). For each pixel, calculate distance squared from the image center (width/2, height/2), compute Gaussian weight using exp(-dist_sq / (2.0 * (max(width, height) * max(width, height) / 16.0))), multiply weight by 100 and round to int, then add to hist[val] (val is the pixel value).
If gray_level is between 0 and 255, return hist[gray_level]; otherwise return 0.
Note: Handle BMP pixel storage order (bottom to top), check file paths before reading, and apply Gaussian weighting for histogram calculation.
function_header: int problem_2_1(const string& filename, int gray_level)
test_cases: // ==================== Main function: Testing ====================
int main() {
    // Set random seed
    srand(42);
    
    cout << fixed << setprecision(6);
    cout << "Problem 2.1" << endl;
    
    int correct_count = 0;
    
    // Test 1
    int correct1 = 589214;  // Expected value (updated from actual output)
    string x1 = "1.bmp";
    int a1 = 128;
    int result1 = problem_2_1(x1, a1);
    cout << "Test 1 result: " << result1 << endl;
    if (result1 == correct1) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct1 << ", Got: " << result1 << endl;
    }
    
    // Test 2
    int correct2 = 628176;  // Expected value (updated from actual output)
    string x2 = "1.bmp";
    int a2 = 64;
    int result2 = problem_2_1(x2, a2);
    cout << "Test 2 result: " << result2 << endl;
    if (result2 == correct2) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct2 << ", Got: " << result2 << endl;
    }
    
    // Test 3
    int correct3 = 943328;  // Expected value (updated from actual output)
    string x3 = "1.bmp";
    int a3 = 200;
    int result3 = problem_2_1(x3, a3);
    cout << "Test 3 result: " << result3 << endl;
    if (result3 == correct3) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct3 << ", Got: " << result3 << endl;
    }
    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 2
step_description_prompt: Please write a C++ function named problem_2_2 that takes a const string& filename as input and returns an int. This function reads a BMP file, computes a weighted histogram peak using a multi-Gaussian weighting scheme, and returns the peak gray level.
The function signature is int problem_2_2(const string& filename).
First, define two structs BMPFileHeader and BMPInfoHeader with #pragma pack(push, 2) and #pragma pack(pop) for 2-byte alignment. BMPFileHeader contains char bfty[2], int bfsize, short bfreserved1, short bfreserved2, int bfoffbit. BMPInfoHeader contains int bisize, int biwidth, int biheight, short biplanes, short bibitcount, int bicompression, int bisizeimage, int bix, int biy, int biclrused, int biclrimportant. Initialize a vector<int> hist(256, 0). Try possible paths ("test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, "substep/test_data/" + filename, filename) to find the existing file. Open the file in binary mode, read BMPFileHeader and BMPInfoHeader. If the file is a BMP (bfty[0] == 'B' and bfty[1] == 'M'), get width (biwidth) and height (abs(biheight)). For 8-bit BMP (bibitcount == 8), skip 1024 bytes of palette. Calculate aligned width as ((width + 3) / 4) * 4, read pixel data into a dynamic unsigned char array. Traverse pixels with actual_row = height - 1 - i (BMP stores from bottom to top), update hist with pixel values. Compute weighted count for each gray level (0-255) using multi-Gaussian weights: centers 64, 128, 192; sigmas 30, 50, 40; mix weights 0.3, 0.4, 0.3. Combined weight is mix_weight1*exp(-(i-center1)^2/(2*sigma1^2)) + mix_weight2*exp(-(i-center2)^2/(2*sigma2^2)) + mix_weight3*exp(-(i-center3)^2/(2*sigma3^2)). Find the gray level with maximum weighted count (hist[i] * combined_weight) as peak_level. If the file is not found, output "Error: Cannot find data file" to cerr and return -1. Handle file operations in binary mode, use ifstream for file reading.
function_header: int problem_2_2(const string& filename)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 2.2" << endl;
    
    int correct_count = 0;
    
    // Test 1
    int correct1 = 255;  // Expected value
    string x1 = "1.bmp";
    int result1 = problem_2_2(x1);
    if (result1 == correct1) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
    }
    
    // Test 2
    int correct2 = 255;  // Expected value
    string x2 = "a.bmp";
    int result2 = problem_2_2(x2);
    if (result2 == correct2) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
    }
    
    // Test 3
    int correct3 = 255;  // Expected value
    string x3 = "b.bmp";
    int result3 = problem_2_2(x3);
    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_2_3 that takes a const string& filename and an int k as parameters and returns a long long. The function calculates a weighted cumulative histogram sum for the first k+1 intensity values of a BMP image, using exponential decay weighting, after reading the image from possible file paths.

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

Algorithm flow:
1. Define packed BMPFileHeader (with bfty[2], bfsize, bfreserved1, bfreserved2, bfoffbit) and BMPInfoHeader (bisize, biwidth, biheight, biplanes, bibitcount, bicompression, bisizeimage, bix, biy, biclrused, biclrimportant) using #pragma pack(push,2) and #pragma pack(pop).
2. Initialize a vector<int> hist(256, 0) for histogram calculation.
3. Try possible file paths: "test_data/" + filename, "substep/test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, filename. Use the first existing path.
4. Open the file in binary mode. If opened, read BMPFileHeader and BMPInfoHeader. Check if the file is a BMP (bfty[0] == 'B' && bfty[1] == 'M').
5. For a valid BMP, get width (infoHeader.biwidth) and height (abs(infoHeader.biheight)). If bibitcount is 8, skip 1024 bytes (palette). Calculate aligned_width as ((width + 3)/4)*4, read pixels into a dynamically allocated array.
6. Compute histogram: iterate pixels (BMP stores rows from bottom to top, so actual_row = height - 1 - i for each i). Increment hist[val] for each pixel value val.
7. Delete the pixel array. Close the file.
8. Calculate weighted cumulative sum: for i from 0 to min(k,255), compute weight as 1.0 + 0.2*exp(-(i - k)*(i - k)/200.0), multiply by hist[i], add to cumulative (cast to long long).
9. Return cumulative.

Use ifstream for file operations (binary mode). Assume necessary headers (<iostream>, <fstream>, <vector>, <string>, <cmath>) are included. Dynamically allocate/deallocate the pixel array with new[]/delete[].
function_header: long problem_2_3(const string& filename, int k)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 2.3" << endl;
    
    int correct_count = 0;
    
    // Test 1
    long long correct1 = 1229946;  // Expected value (updated from actual output)
    string x1 = "1.bmp";
    int k1 = 128;
    long long result1 = problem_2_3(x1, k1);
    if (result1 == correct1) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct1 << ", Got: " << result1 << endl;
    }
    
    // Test 2
    long long correct2 = 336859;  // Expected value (updated from actual output)
    string x2 = "1.bmp";
    int k2 = 64;
    long long result2 = problem_2_3(x2, k2);
    if (result2 == correct2) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct2 << ", Got: " << result2 << endl;
    }
    
    // Test 3
    long long correct3 = 2275125;  // Expected value (updated from actual output)
    string x3 = "1.bmp";
    int k3 = 200;
    long long result3 = problem_2_3(x3, k3);
    if (result3 == correct3) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << correct3 << ", Got: " << result3 << endl;
    }
    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

step_number: 4
step_description_prompt: Please write a C++ function named problem_2_4 that takes a const string& filename and an int k, returns a double. The function processes a BMP image to calculate a weighted cumulative histogram value up to intensity k and scales it to 0-255.

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

Algorithm flow:
1. 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) using #pragma pack(push, 2) before and #pragma pack(pop) after.
2. Initialize a 256-bin histogram (vector<int> hist(256, 0)) and set width=600, height=600 by default.
3. Check possible file paths in order: "test_data/" + filename, "substep/test_data/" + filename, "../test_data/" + filename, "../../test_data/" + filename, filename. Use the first existing path. If no file is found, output "Error: Cannot find data file" to cerr and return -1.0.
4. Open the BMP file, read BMPFileHeader and BMPInfoHeader. If bfty[0] == 'B' and bfty[1] == 'M', update width to biwidth and height to abs(biheight).
5. Read pixel data: if bibitcount == 8, skip 1024 bytes (palette). Calculate aligned_width as ((width + 3) / 4) * 4. Read aligned_width * height pixels into a buffer. Note BMP stores pixels from bottom to top (actual_row = height - 1 - i when iterating row i).
6. Compute histogram by iterating all pixels (i from 0 to height-1, j from 0 to width-1): get val from pixels[actual_row * aligned_width + j], increment hist[val].
7. Calculate weighted cumulative sum: initialize cumulative to 0. For i from 0 to min(k, 255), compute weight = 1.0 + 0.1 * exp(-(i - k) * (i - k) / 200.0), add (long long)(hist[i] * weight) to cumulative.
8. Return cumulative * 255.0 / (width * height).

Assume existing functions (e.g., ifstream, vector, exp) are pre-defined. Handle BMP file reading with path checking, header parsing, and pixel alignment.
function_header: double problem_2_4(const string& filename, int k)
test_cases: // ==================== Main function: Testing ====================
int main() {
    srand(42);
    cout << fixed << setprecision(6);
    cout << "Problem 2.4" << endl;
    
    int correct_count = 0;
    const double tolerance = 1e-5;
    
    // Test 1
    double correct1 = 46.110410;  // Expected value (updated from actual output)
    string x1 = "1.bmp";
    int k1 = 128;
    double result1 = problem_2_4(x1, k1);
    if (abs(result1 - correct1) < tolerance) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << fixed << setprecision(6) << correct1 << ", Got: " << result1 << endl;
    }
    
    // Test 2
    double correct2 = 12.193987;  // Expected value (updated from actual output)
    string x2 = "1.bmp";
    int k2 = 64;
    double result2 = problem_2_4(x2, k2);
    if (abs(result2 - correct2) < tolerance) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << fixed << setprecision(6) << correct2 << ", Got: " << result2 << endl;
    }
    
    // Test 3
    double correct3 = 85.502235;  // Expected value (updated from actual output)
    string x3 = "1.bmp";
    int k3 = 200;
    double result3 = problem_2_4(x3, k3);
    if (abs(result3 - correct3) < tolerance) {
        cout << "Correct" << endl;
        correct_count++;
    } else {
        cout << "Wrong" << endl;
        cout << "Expected: " << fixed << setprecision(6) << correct3 << ", Got: " << result3 << endl;
    }
    
    if (correct_count == 3) {
        cout << "Completely correct!" << endl;
    }
    
    return 0;
}

General solution:

General tests: