【问题标题】:How do I crop a bitmap image on an ESP32-CAM?如何在 ESP32-CAM 上裁剪位图图像?
【发布时间】:2021-08-11 08:24:39
【问题描述】:

我整晚都在敲打这段代码。我正在尝试在 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。

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

代码如此简单,这让我抓狂。谢谢

Image very similar to the original Cropped - note not original bmp - a screenshot - but shows issue

【问题讨论】:

    标签: bitmap arduino-ide arduino-esp32


    【解决方案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;
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 2015-08-10
      • 2016-01-11
      • 2015-05-05
      • 2021-01-15
      • 1970-01-01
      相关资源
      最近更新 更多