使用C++结合CImg库实现Sobel边缘检测时图像被裁剪一半且触发munmap_chunk()内存错误的问题
Hey there! Let's break down what's going wrong with your Sobel edge detection code and fix those issues—both the crash and the half-displayed image.
Two key issues are causing your problems: incorrect coordinate handling in CImg, and a minor type mismatch that's leading to unexpected behavior. Let's walk through them step by step.
1. CImg Coordinate Mix-Up (Root of Both Problems)
CImg uses the convention image(x, y) where:
x= column index (ranges from 0 towidth()-1)y= row index (ranges from 0 toheight()-1)
In your code, you swapped these coordinates everywhere, which leads to:
- Out-of-bounds memory access: Triggering the
munmap_chunk(): invalid pointercrash when you try to read/write pixels outside the image's actual dimensions. - Half-displayed image: You're writing to the wrong parts of the output buffer, so only a portion of the edge data ends up in the correct place.
Specific fixes needed:
- You were accessing
output(j, i)instead ofoutput(i, j)(swapped column/row order) - Your neighbor pixel calculation was backwards:
np_x = j + (m - 1)should benp_x = i + (m - 1), andnp_y = i + (n - 1)should benp_y = j + (n - 1)
2. Gradient Type Mismatch
Storing gradient values in int variables (gradient_x, gradient_y) while multiplying by a float pixel value truncates decimal precision unnecessarily, and could lead to integer overflow with large gradient values. Switching these to float preserves precision and avoids overflow issues.
Fixed Code
Here's your code with all corrections applied:
#include <iostream> #include <cmath> // Added for sqrt() - implicit includes aren't portable! #include <omp.h> #include "CImg.h" using namespace std; using namespace cimg_library; int main() { const int x_mask[9] = { -1, 0, 1, -2, 0, 2, -1, 0, 1 }; const int y_mask[9] = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; const char* fileName = "test.png"; CImg<float> img(fileName); int cols = img.width(); int lines = img.height(); CImg<float> output(cols, lines, 1, 1, 0.0); printf("Loading %d x %d image...\n", cols, lines); const int mask_size = 3; float gradient_x; // Changed to float for precision float gradient_y; // Changed to float for precision // Loop through rows first (matches CImg's row-major memory layout for better cache performance) for (int j = 1; j < lines - 1; j++) { // j = row index (y-axis) for (int i = 1; i < cols - 1; i++) { // i = column index (x-axis) gradient_x = 0.0f; gradient_y = 0.0f; // Calculate gradients with correct coordinate mapping for (int m = 0; m < mask_size; m++) { for (int n = 0; n < mask_size; n++) { int np_x = i + (m - 1); // Neighbor column int np_y = j + (n - 1); // Neighbor row float v = img(np_x, np_y); int mask_index = (m * 3) + n; gradient_x += x_mask[mask_index] * v; gradient_y += y_mask[mask_index] * v; } } float gradient_sum = sqrt(gradient_x * gradient_x + gradient_y * gradient_y); // Cleaner value clamping with std::min/max gradient_sum = std::max(0.0f, std::min(gradient_sum, 255.0f)); output(i, j) = gradient_sum; // Correct coordinate order for output } } printf("Output image of size %d x %d\n", output.width(), output.height()); output.save("test_edges.png"); return 0; }
Quick Extra Tips
- I added
<cmath>explicitly—your original code might have been relying on implicit includes from CImg, which isn't reliable across compilers. - Reordered the loops to iterate over rows first, which matches how CImg stores pixel data in memory. This is a small optimization that improves cache performance.
内容的提问来源于stack exchange,提问作者Phil

