6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonとCとの連携(ctypes活用)~画像ファイルの生成~

Last updated at Posted at 2024-10-20

はじめに

Qiitaへの投稿、久しぶりになりました。

私は、最近(一昨年ぐらい?)、Pythonを少し覚えて、まだまだ初心者ですが、業務で使用するツール的プログラムをちょこちょこと作成しています。

で、私は、Cのプログラマー歴は一応長いので、

  • Cで書いた方が早い、とか、
  • Pythonの変数って実際にはどうメモリ上に配置されているんだろう?

などと、よく考えることがありました。そして、今回、Pythonに、ctypesというライブラリがあって、結構、便利に使えそうだと気づきましたので、ちょっと試してみました。それをこの場にシェアしたいと思います。

画像ファイルの生成

今回、垂直カラーバーを一例に、画像ファイルを生成するプログラムを書いてみました。カラーバーのイメージを作っているのは、C言語による関数get_color_bar_imageで、それをPythonプログラムから呼び出すことで、その画像を取り扱っています。

C側

unsigned char *get_color_bar_image(unsigned int *pHeight, unsigned int *pWidth)
{
  *pWidth = IMG_WIDTH;
  *pHeight = IMG_HEIGHT;

  return generate_color_bar_image(IMG_WIDTH, IMG_HEIGHT, NUM_OF_COLOR_BARS, colors_of_color_bars, kFalse, kRGB_Order);
}

公開用の関数get_color_bar_imageは、さらにサブ関数generate_color_bar_imageを呼び出す形としていて、このサブ関数内で、実際のカラーバー生成の処理を記述しています。

static unsigned char *generate_color_bar_image(int width, int height, int num_of_color_bars, void *table, int pixel_interleaved, int color_order)
{
  int	i, j, k;
  unsigned char	*red, *green, *blue, *image;
  unsigned char *color_bar_table = (unsigned char *)table;
  
  image = (unsigned char *)malloc(width * height * IMG_COLOR_FACTOR);

  if (!pixel_interleaved) {	// 面順次
    red = image;
    green = red + width * height;
    blue = green + width * height;
  } else if (color_order == kRGB_Order) {	// 点順次
    red = image;
    green = image + 1;
    blue = image + 2;
  } else {
    blue = image;
    green = image + 1;
    red = image + 2;
  }

  for (j = 0; j < height; j++) {
    for (k = 0; k < num_of_color_bars; k++) {
      for (i = 0; i < width / num_of_color_bars; i++) {
	*red = *color_bar_table;
	*green = *(color_bar_table + 1);
	*blue = *(color_bar_table + 2);
	if (!pixel_interleaved) {	// 面順次
	  red++;
	  green++;
	  blue++;
	} else {	// 点順次
	  red += 3;
	  green += 3;
	  blue += 3;
	}
      }
      color_bar_table += IMG_COLOR_FACTOR;
    }
    color_bar_table = (unsigned char *)table;
  }

  return image;
}

Python側

関数get_color_bar_imageが、共有ライブラリファイルがlibcolorbar.soの中で定義されているとして、

test.py
lib = ctypes.cdll.LoadLibrary("./libcolorbar.so")

lib.get_color_bar_image.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)]
lib.get_color_bar_image.restype = ctypes.c_void_p

と記述することで、関数get_color_bar_imageの引数や返り値の型を明文化しています。そして、実際に、関数get_color_bar_imageを使用するときは、

test.py
    refHeight = ctypes.c_int32()
    refWidth = ctypes.c_int32()
    img_pointer = lib.get_color_bar_image(refHeight, refWidth)

という感じになります。

通常、C言語で関数get_color_bar_imageを呼び出す場合は、引数や返り値の型を合わせて使うことになるわけですが、Pythonから使う場合は、上記のように、それらのインタフェース情報を指定することで、Pythonの世界で扱えるようになる、という風に言えるかと思います。

        width = refWidth.value
        height = refHeight.value

        # ポインタからデータをバイト配列に変換
        buffer_size = width * height

        # ctypes.string_atを使用してポインタからデータを取得
        red_data = ctypes.string_at(img_pointer, buffer_size)
        green_data = ctypes.string_at(img_pointer + buffer_size, buffer_size)
        blue_data = ctypes.string_at(img_pointer + 2 * buffer_size, buffer_size)

そして、lib.get_color_bar_imageで得られたimg_pointerを用いて、ctypes.string_atを用いて、

  • REDデータを変数red_dataに
  • GREENデータを変数green_dataに
  • BLUEデータを変数blue_dataに、

それぞれ、取得してやって、ここまでくれば、Pythonで画像を扱うことになれている人は、扱えますね。
あとは、PythonのPillowライブラリのfrombytesmergeを使って、一つの画像に統合して、動的に、ユーザに出力したい画像ファイルフォーマットの拡張子を指定させて、saveを使えば簡単に画像ファイルが生成できてしまいます。

C言語での画像ファイルの生成

C言語でも、BMPファイル、JPEGファイル、TIFFファイル、を生成する例を記述してみていますので、ご参考になれば、と思います。

BMPファイル生成は、自分でヘッダを用意して、画像の縦横サイズやデータ長をそのヘッダに埋め込みつつファイル化しています。

JPEGはjpeglibを、TIFFはlibtiffを、それぞれ利用しています。

本サンプルプログラムの置き場所

現時点では、Raspberry Pi 5NVIDIA Jetson Orin Nanoにて動作を確認しています。

リンク集

誰でもググるとすぐ見つかるリンクですが、一応、この場にて紹介させて下さい。

https://qiita.com/nabion/items/594fb3316583130a636e
https://qiita.com/laddge/items/fa15b180d206e4175af8

私も、これらの皆さんの記事は一応読んだ上で、今回、PythonとCとの連携を試したり、この記事を書いたりしています。

おわりに

以上、PythonとCとを連携させたサンプルプログラムの紹介でした。

自分で作れるはっきりとした処理内容があって、それはCで記述しつつ、Pythonからは、そのCでの処理をお手軽に再利用しつつ、例えば、今回のように、よく知られたファイルフォーマットに変換して可視化する、みたいに、Pythonの環境にお任せしてさくっとやりたいことを実現する、そんなときに、このPythonCとの連携は活躍しそうです

もう少し、いろいろと説明入れてみようと思っていたのですが、、、このレベルでの公開になってしまいました。

ちなみに、最近の若い人は、ネット上のサンプルプログラムを適当に再利用したり、今ならば、ChatGPT君にプログラム作ってもらったり、などとできますよね?私も時々お世話になっています。ですが、そういう便利な世の中になっても、なんでも丸投げしていると、知見が蓄積できないかと思いますので、自分のこだわる領域だけでも、自分で作ってみるのがいいんじゃないかな、と思っています。

以上、PythonCとで連携してやりたいことを実現する例として、画像ファイルの生成の実現例を紹介してみました。

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?