GIMP & Pythonで画像編集 ~ 画像の回転


はじめに - この記事でやりたいこと

写真の撮影時に生じた傾きを補正したい。これ自体は各種レタッチソフトでできる。
しかし、枚数が増えると1枚1枚角度を指定するのが面倒。
そこでGIMPのPythn-Fuを利用して、ある程度の操作を自動化することにする。
(PhotoShopの「ものさしツール」のようなことをやりたい)

▼左画像の赤線のように水平の基準を指定して回転させたい

方法

以下のような方法でやりたいこと実現します。

回転の基準となる直線を選択する

GIMPでは直線を選択することはできないので矩形選択で代用します。
時計回りの場合は右上と左下を結んだ直線、反時計回りの場合は左上と右下を結んだ直線が基準の直線になります。

作成したPython-fuを実行する

Python-fuの処理は以下のような流れです。

  1. GIMPのUIで時計回り・反時計回りを選択する(引数で主処理へ渡す)
  2. 回転角度を算出する。
  3. 回転後のサイズに合わせて描画領域を拡大する。
  4. 回転処理を実行する。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import math
from gimpfu import *

# 画像の回転
################
def rotate_image(img,radian):
    # レイヤーの選択
    lay=img.active_layer

    # 回転時に必要となる余白の計算
    width=img.width
    height=img.height

    abs_radian = abs(radian)
    new_width=int(round(math.cos(abs_radian)*width+math.cos(math.pi/2-abs_radian)*height,0))
    new_hight=int(round(math.sin(abs_radian)*width+math.sin(math.pi/2-abs_radian)*height,0))

    # リサイズ・移動
    img.resize(new_width,new_hight,0)
    lay.translate((new_width-width)/2, (new_hight-height)/2)

    # 回転
    pdb.gimp_item_transform_rotate(lay ,radian ,TRUE ,0 ,0)

# 主処理
################
def plugin_main(image, layer,radio):

    # undoグループの開始
    pdb.gimp_image_undo_group_start(image)

    # 処理対象の画像を取得
    img=gimp.image_list()[0]

    #回転角度の算出
    ## 選択範囲の座標を取得
    non_empty,x1,y1,x2,y2=pdb.gimp_selection_bounds(img)

    ## ラジアンの導出
    if radio=="0":
        # 反時計回り
        radian = math.atan2(y1-y2, x2-x1)
    else:
        # 時計回り
        radian = math.atan2(y2-y1, x2-x1)

    ## 選択範囲が残ったままだと回転時に選択範囲のみが回転対象となるのでクリア
    pdb.gimp_selection_none(img)

    # 回転の実行
    rotate_image(img, radian)

    # undoグループの終了
    pdb.gimp_image_undo_group_end(image)

register(
    "rotate",#コマンドラインまたはスクリプトから呼び出す場合のコマンドの名前
    "rotate",#プラグインの説明
    "rotate",#プラグインの詳細な説明
    "am(author)",#プラグインの作成者
    "am(author)",#プラグインの著作権保有者
    "2020/04/05",#著作権の日付
    "<Image>/Filters/Languages/Python-Fu/rotate", #メニューの中でプラグインに使用されるラベル
    "RGB*, GRAY*", #プラグインで処理する対象となる画像のタイプ
    [(PF_RADIO, "PF_RADIO", "direction of rotation?", "clockwise", (("clockwise", "1"), ("anticlockwise", "0"))),],#引数
    [], # 戻り値
    plugin_main) # メソッド名

main()

残課題

  • 複数レイヤーを扱う場合
    今回はデジカメで撮影した画像の編集、という目的なのでレイヤは1枚であることが前提です。
    複数レイヤを扱う場合、修正が必要になります。

  • 複数画像を開いている場合
    gimp.image_list()[0]で取得される画像はGIMPで最後に開いた画像になります。
    本来であれば、Python-Fu実行時点でアクティブな画像を取得できるのが望ましいですが、どうやら簡単に取得する方法はないようです。active_layerのように取得できれば楽なのですが。
    参考:Get currently active image in python (2012) — GIMP Development — gimpusers.com

参考にした記事

GIMPのスクリプト(python-fu)のつくり方について書くで?🤜🤛 - Qiita
テンプレートはこちらから拝借しました

GIMP Library Reference Manual
GIMPのライブラリリファレンス