このページでは、画像のトリミングについての説明と、そのプログラムの例の紹介を行います。
Contents
画像のトリミング
まず画像のトリミングについて説明します。
画像のトリミングとは、ある座標からある座標への領域内の画像部分を切り取り、切り取った部分のみの画像を生成する処理です。
下の図がイメージつきやすいと思います。
画像のトリミングのプログラム
さっそく画像のトリミングを行うプログラムを紹介していきたいと思います。
スポンサーリンク
ソースコード
下記が画像のトリミングを行うプログラムのソースコード例になります。
#include "myJpeg.h"
int main(int argc, char *argv[]){
BITMAPDATA_t bitmap, trimmedBitmap;
int x, y, c;
int sx, sy, ex, ey;
char outname[256];
if(argc != 2){
printf("ファイル名指定してください\n");
return -1;
}
if(jpegFileReadDecode(&bitmap, argv[1]) == -1){
printf("jpegFileReadDecode error\n");
return -1;
}
printf("開始点のX座標は?");
scanf("%d", &sx);
if(sx < 0 || sx >= bitmap.width - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("開始点のY座標は?");
scanf("%d", &sy);
if(sy < 0 || sy >= bitmap.height - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("終了点のX座標は?");
scanf("%d", &ex);
if(ex < 0 || ex >= bitmap.width - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("終了点のY座標は?");
scanf("%d", &ey);
if(ey < 0 || ey >= bitmap.height - 1) {
printf("座標がおかしいです\n");
return -1;
}
/* 座標の大小関係が逆の場合はエラー */
if(sx > ex) {
printf("X座標の開始点と終了点の大小関係が逆です\n");
return -1;
}
if(sy > ey) {
printf("Y座標の開始点と終了点の大小関係が逆です\n");
return -1;
}
trimmedBitmap.width = ex - sx + 1;
trimmedBitmap.height = ey - sy + 1;
trimmedBitmap.ch = bitmap.ch;
printf("width = %d, height = %d, ch = %d\n", trimmedBitmap.width, trimmedBitmap.height, trimmedBitmap.ch);
trimmedBitmap.data = (unsigned char*)malloc(sizeof(unsigned char) * trimmedBitmap.width * trimmedBitmap.height * trimmedBitmap.ch);
if(trimmedBitmap.data == NULL){
printf("maloc err\n");
return -1;
}
/* ここから画像処理 */
for(y = 0; y < trimmedBitmap.height; y++){
for(x = 0; x < trimmedBitmap.width; x++){
for(c = 0; c < trimmedBitmap.ch; c++){
trimmedBitmap.data[((y * trimmedBitmap.width) + x) * trimmedBitmap.ch + c]
= bitmap.data[(((y + sy) * bitmap.width) + (x + sx)) * bitmap.ch + c];
}
}
}
/* ここまで画像処理 */
sprintf(outname, "%s", "trimmed.jpg");
if(jpegFileEncodeWrite(&trimmedBitmap, outname) == -1){
printf("jpegFileEncodeWrite error\n");
freeBitmapData(&bitmap);
return -1;
}
freeBitmapData(&trimmedBitmap);
freeBitmapData(&bitmap);
return 0;
}
jpegFileReadDecode
や jpegFileEncodeWrite
、BITMAPDATA_t
などは下記ページで公開している myJpeg.c
と myJpeg.h
で定義していますので、コンパイルを行いたい方は事前にコピペして入手してきてください。
コンパイルと実行
例えば下記コマンドによりソースコードをコンパイルし、実行可能ファイルを作成することができます。
gcc myJpeg.c trimming.c -o main.exe -ljpeg
gcc に指定する各ファイルは下記のようになります。
main.c
:このページで公開しているソースコードmyJpeg.c
:JPEG 関連の関数を定義したソースコードmyJpeg.h
:JPEG 関連の構造体等を定義したソースコードmain.exe
:作成される実行可能ファイル
-ljpeg
は libjpeg へのリンクを行うためのオプションです。
コンパイルを行う場合は libjpeg のインストールが必要になりますので、まだインストールしていない方は下記ページ等を参考にして事前に libjpeg をインストールしておいてください。
【C言語】libjpegのインストールと使用方法・使用例myJpeg.c
や myJpeg.h
も上記ページで公開しています。
実行時には、トリミングを行いたい JPEG 画像へのファイルパスを指定します。
例えば main.exe
と同じフォルダにある input.jpg
をトリミングするのであれば下記のようにして引数を指定して main.exe
を実行します。
./main.exe inut.jpg
実行すると、下記のようにトリミングの開始点や終了点の入力が促されますのでトリミングしたい座標を指定すれば、トリミング後の JPEG ファイル trimmed.jpg
が main.exe
と同じフォルダに作成されます。
./main.exe input.jpg width = 640, height = 427, ch = 3 開始点のX座標は?100 開始点のY座標は?100 終了点のX座標は?200 終了点のY座標は?200 width = 101, height = 101, ch = 3
プログラムの説明
それでは先ほど紹介したソースコードのプログラムについて解説をしていきたいと思います。
スポンサーリンク
トリミング領域の取得
下記でトリミングする領域を指定できるようにしています。
この指定された座標 (sx
, sy
) と座標 (ex
, ey
) を基にトリミングを行います。
より具体的には入力画像の座標 (sx
, sy
) から座標 (ex
, ey
) の領域をトリミングします。座標 (ex
, ey
) も含まれる点に注意してください。
一応座標が画像の外にある場合はエラー終了するようにしています。
printf("開始点のX座標は?");
scanf("%d", &sx);
if(sx < 0 || sx >= bitmap.width - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("開始点のY座標は?");
scanf("%d", &sy);
if(sy < 0 || sy >= bitmap.height - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("終了点のX座標は?");
scanf("%d", &ex);
if(ex < 0 || ex >= bitmap.width - 1) {
printf("座標がおかしいです\n");
return -1;
}
printf("終了点のY座標は?");
scanf("%d", &ey);
if(ey < 0 || ey >= bitmap.height - 1) {
printf("座標がおかしいです\n");
return -1;
}
JPEGファイルの読み込み・書き込み
jpegFileReadDecode
関数と jpegFileEncodeWrite
関数はそれぞれ JPEG を読み込む関数・JPEG を保存する関数(JPEG の書き込みを行う関数)になります。
詳細は下記ページで解説していますので、詳しく知りたい方は下記ページをご参照ください。
【C言語】libjpegのインストールと使用方法・使用例トリミング後画像のメモリ確保
トリミング後画像は元画像に比べてサイズが小さくなります。
指定された sx
、sy
、ex
、ey
に基づいて画像サイズを計算し、その画像サイズの分だけ malloc
関数でメモリ領域を確保しています。
trimmedBitmap.width = ex - sx + 1;
trimmedBitmap.height = ey - sy + 1;
trimmedBitmap.ch = bitmap.ch;
printf("width = %d, height = %d, ch = %d\n", trimmedBitmap.width, trimmedBitmap.height, trimmedBitmap.ch);
trimmedBitmap.data = (unsigned char*)malloc(sizeof(unsigned char) * trimmedBitmap.width * trimmedBitmap.height * trimmedBitmap.ch);
if(trimmedBitmap.data == NULL){
printf("maloc err\n");
return -1;
}
スポンサーリンク
トリミング処理
実際のトリミング処理は下記のループの中で行っています。
for(y = 0; y < trimmedBitmap.height; y++){
for(x = 0; x < trimmedBitmap.width; x++){
for(c = 0; c < trimmedBitmap.ch; c++){
trimmedBitmap.data[((y * trimmedBitmap.width) + x) * trimmedBitmap.ch + c]
= bitmap.data[(((y + sy) * bitmap.width) + (x + sx)) * bitmap.ch + c];
}
}
}
x
と y
はトリミング後画像上の座標であり、それぞれ x
は横方向、y
は縦方向の座標としています。
一方、m
と n
は元画像上の座標であり、それぞれ m
は横方向、n
は縦方向の座標としています。
ループの中で行っているのは、トリミング後画像の座標 (x
, y
) に対して元画像の座標 (x + sx
, y + sy
) の画素のコピーです。
これをトリミング後画像の幅・高さ(幅:ex - sx
、高さ:ey - sy
)分行なっていますので、指定された開始点と終了点の間の領域のみがコピーされ、結果的にトリミング後画像を得ることができます。
トリミング後の画像
最後にこのページで紹介したプログラムでトリミングした結果を紹介しておきます。
・トリミング前(画像サイズ364 x 500)
・トリミング後(開始点[82, 100]、終了点[282, 400]でトリミング)
まとめ
このページではC言語で画像をトリミング・切り抜きする方法とそのプログラム例について解説しました。
複数枚の画像を完全に同じサイズに切り抜きするときなどにかなり使えますのでぜひ参考にしていただければと思います。