0

我整晚都在敲打这段代码。我正在尝试在 ESP32 CAM 上裁剪位图。我拍了一张照片,将照片转换为 bmp,然后调用以下函数:

size_t crop_image(uint8_t *fb, size_t len, uint32_t width, uint32_t height, unsigned short crop_left, unsigned short crop_top, unsigned short crop_width, unsigned short crop_height)
  {

    uint8_t *buf = fb + BMP_HEADER_LEN;
    size_t new_size = crop_width * crop_height * 3 + BMP_HEADER_LEN;

    unsigned int write_idx = 0;
    for(uint32_t y = crop_top * 3; y < (crop_top + crop_height) * width * 3; y += width * 3){
      for(int x = crop_left * 3; x < (crop_left + crop_width) * 3; x += 3){
        int pix_idx = x + y;
        buf[write_idx++] = buf[pix_idx];
        buf[write_idx++] = buf[pix_idx+1];
        buf[write_idx++] = buf[pix_idx+2];
      }
    }

    // Adjust the BMP Header
    *(uint32_t *)(fb + BMP_HEADER_WIDTH_OFFSET) = crop_width;
    *(uint32_t *)(fb + BMP_HEADER_HEIGHT_OFFSET) = -1 * crop_height;
    *(uint32_t *)(fb + 6) = new_size;
    *(uint32_t *)(fb + 34) = crop_width * crop_height * 3;

    return new_size;
  }

这几乎可以工作。如果我将图像的宽度和高度作为crop_width 和crop_height 参数传递,则输出与原始参数相同。如果我通过较小的高度和全宽,那么它也可以工作。当我传入一个小于原始宽度的crop_width 时,我得到一个图像,其对角线“​​移位”线从右上角延伸到底部约1/3 处。看起来我的宽度偏离了一个字节,导致 3/2 斜线。但我无法弄清楚是什么原因。

我附上了一个全尺寸的 jpg 和一个裁剪的位图。请注意,jpg 不是源(我的代码不保存原件),但与裁剪图像的源非常相似。裁剪后的 bmitmap 是通过使用crop_left = 0、crop_top = 0、crop_width = 799、crop_height = 600 的调用创建的。原始图像为 800x600。

我已经删除了所有额外的代码 - 所以没有错误处理,没有从位图标题中提取宽度/高度等。

代码如此简单,这让我发疯。谢谢

图像与原始裁剪非常相似 - 注意不是原始 bmp - 屏幕截图 - 但显示问题

4

1 回答 1

1

好的,几个小时的睡眠可以做什么,真是太神奇了。裁剪后的图像宽度需要填充为 4 字节的倍数。我正在测试的数字恰好不能被 4 整除(整个图像测试除外)。位图图像宽度必须在 4 字节边界上 - 或填充为这样,

谢谢你的考虑

这是工作代码(仍然没有错误处理):

size_t crop_image(uint8_t *fb, size_t len, uint32_t width, uint32_t height, unsigned short crop_left, unsigned short crop_top, unsigned short crop_width, unsigned short crop_height)
  {

    uint8_t *buf = fb + BMP_HEADER_LEN;
    size_t new_size = crop_width * crop_height * 3 + BMP_HEADER_LEN;


    unsigned int write_idx = 0;
    for(uint32_t y = crop_top * 3; y < (crop_top + crop_height) * width * 3; y += width * 3){
      for(int x = crop_left * 3; x < (crop_left + crop_width) * 3; x += 3){
        int pix_idx = x + y;
        buf[write_idx++] = buf[pix_idx];
        buf[write_idx++] = buf[pix_idx+1];
        buf[write_idx++] = buf[pix_idx+2];
      }
      // Pad to four byte boundary
      for (int i_pad=0; i_pad < (crop_width % 4); i_pad++) buf[write_idx++] = 0;
    }

    // Adjust the BMP Header
    *(uint32_t *)(fb + BMP_HEADER_WIDTH_OFFSET) = crop_width;
    *(uint32_t *)(fb + BMP_HEADER_HEIGHT_OFFSET) = -1 * crop_height;
    *(uint32_t *)(fb + 6) = new_size;
    *(uint32_t *)(fb + 34) = crop_width * crop_height * 3;

    return new_size;
  }
于 2021-05-22T19:19:25.520 回答