C言語で画像の切り抜き・トリミング

このページでは、画像のトリミングについての説明と、そのプログラムの例の紹介を行います。

画像のトリミング

まず画像のトリミングについて説明します。

画像のトリミングとは、ある座標からある座標への領域内の画像部分を切り取り、切り取った部分のみの画像を生成する処理です。下の図がイメージつきやすいと思います。

プログラム例

main.c
#include "myJpeg.h"

int main(int argc, char *argv[]){

  RAWDATA_t raw, trimmedRaw;
  int x, y, c;
  int sx, sy, ex, ey;
  char outname[256];

  if(argc != 2){
    printf("ファイル名指定してください\n");
    return -1;
  }

  if(jpegFileReadDecode(&raw, argv[1]) == -1){
    printf("jpegFileReadDecode error\n");
    return -1;
  }

  printf("開始点のX座標は?");
  scanf("%d", &sx);
  if(sx < 0 || sx >= raw.width - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("開始点のY座標は?");
  scanf("%d", &sy);
  if(sy < 0 || sy >= raw.height - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("終了点のX座標は?");
  scanf("%d", &ex);
  if(ex < 0 || ex >= raw.width - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("終了点のY座標は?");
  scanf("%d", &ey);
  if(ey < 0 || ey >= raw.height - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }

  /* 座標の大小関係が逆の場合はエラー */
  if(sx > ex) {
    printf("X座標の開始点と終了点の大小関係が逆です\n");
    return -1;
  }
  if(sy > ey) {
    printf("Y座標の開始点と終了点の大小関係が逆です\n");
    return -1;
  }

  trimmedRaw.width = ex - sx + 1;
  trimmedRaw.height = ey - sy + 1;
  trimmedRaw.ch = raw.ch;
  printf("width = %d, height = %d, ch = %d\n", trimmedRaw.width, trimmedRaw.height, trimmedRaw.ch);

  trimmedRaw.data = (unsigned char*)malloc(sizeof(unsigned char) * trimmedRaw.width * trimmedRaw.height * trimmedRaw.ch);
  if(trimmedRaw.data == NULL){
    printf("maloc err\n");
    return -1;
  }

  /* ここから画像処理 */
  for(y = 0; y < trimmedRaw.height; y++){
    for(x = 0; x < trimmedRaw.width; x++){
      for(c = 0; c < trimmedRaw.ch; c++){
        trimmedRaw.data[((y * trimmedRaw.width) + x) * trimmedRaw.ch + c]
        = raw.data[(((y + sy) * raw.width) + (x + sx)) * raw.ch + c];
      }
    }
  }

  /* ここまで画像処理 */

  sprintf(outname, "%s", "trimmed.jpg");

  if(jpegFileEncodeWrite(&trimmedRaw, outname) == -1){
    printf("jpegFileEncodeWrite error\n");
    freeRawData(&raw);
    return -1;
  }

  freeRawData(&trimmedRaw);
  freeRawData(&raw);

  return 0;
}

スポンサーリンク

プログラムの説明

トリミング領域の取得

下記でトリミングする領域を指定できるようにしています。

この指定された座標(sx, sy)と座標(ex, ey)を基にトリミングを行います。一応座標が画像の外にある場合はエラー終了するようにしています。

  printf("開始点のX座標は?");
  scanf("%d", &sx);
  if(sx < 0 || sx >= raw.width - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("開始点のY座標は?");
  scanf("%d", &sy);
  if(sy < 0 || sy >= raw.height - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("終了点のX座標は?");
  scanf("%d", &ex);
  if(ex < 0 || ex >= raw.width - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }
  printf("終了点のY座標は?");
  scanf("%d", &ey);
  if(ey < 0 || ey >= raw.height - 1) {
    printf("座標がおかしいです\n");
    return -1;
  }

JPEGファイルの読み込み・書き込み

下記記事と全く同じですのでこちらをご参照ください

C言語で画像の拡大縮小(最近傍補間編)

トリミング後画像のメモリ確保

トリミング後画像は元画像に比べてサイズが小さくなります。指定されたsx, sy, ex, eyに基づいて画像サイズを計算し、その画像サイズの分だけmalloc関数でメモリ領域を確保しています。

  trimmedRaw.width = ex - sx + 1;
  trimmedRaw.height = ey - sy + 1;
  trimmedRaw.ch = raw.ch;
  printf("width = %d, height = %d, ch = %d\n", trimmedRaw.width, trimmedRaw.height, trimmedRaw.ch);

  trimmedRaw.data = (unsigned char*)malloc(sizeof(unsigned char) * trimmedRaw.width * trimmedRaw.height * trimmedRaw.ch);
  if(trimmedRaw.data == NULL){
    printf("maloc err\n");
    return -1;
  }

トリミング処理

xとyはトリミング後画像上の座標であり、それぞれ x は横方向、y は縦方向の座標としています。一方、m と n は元画像上の座標であり、それぞれ m は横方向、n は縦方向の座標としています。

下記によりトリミング後画像の座標(x, y)に対して元画像の座標(x + sx, y + sy)をコピーし、これをトリミング後画像の幅・高さに対してコピーを行なっていますので、指定された開始点と終了点の間の領域のみをコピーすることができています。

  for(y = 0; y < trimmedRaw.height; y++){
    for(x = 0; x < trimmedRaw.width; x++){
      for(c = 0; c < trimmedRaw.ch; c++){
        trimmedRaw.data[((y * trimmedRaw.width) + x) * trimmedRaw.ch + c]
        = raw.data[(((y + sy) * raw.width) + (x + sx)) * raw.ch + c];
      }
    }
  }

 

トリミング後の画像

・画像処理前(画像サイズ364 x 500)

・画像処理後(開始点[82, 100]、終了点[282, 400]でトリミング)

まとめ

このページではC言語で画像をトリミング・切り抜きする方法とそのプログラム例について解説しました。複数枚の画像を完全に同じサイズに切り抜きするときなどにかなり使えますのでぜひ参考にしていただければと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です