アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

PHPで作る面白コラージュ写真

こんにちは、牧野です。最近、夏みたいに暑い日が続いていますね。

今日は、これからオフィス移転のための引越準備です。このブログをアップしたら、本格的に片付けです。
今回は、趣味のプログラミングです。ずっと前からやってみたいと思っていたネタがあったので、それを作ってみました。
それは、小さな画像を並べて、全然別の大きな画像を作る、というものです。

今回は、次のような処理の流れににしました。
1.ミニ画像の元となる画像をたくさん用意し、ミニ画像を作成。
2.再現したい大きな画像を用意して、小さく分割。
3.分割した各画像について、ミニ画像の中から一番似ている画像をピックアップ。
4.ピックアップした画像を並べて、新しい画像を作成。

今回のプログラムの要になるのが、「ミニ画像の中からどうやって一番似た画像を見つけるか」というところになります。
ピクセルのRGBの平均、とかやると全然ダメそうな気がしたので調べてみると、いいロジックがありました。

http://d.hatena.ne.jp/aidiary/20091003/1254574041

画像ごとに、各ピクセルの色分布を用意し、一番近い色分布の画像を選ぶ、というものです。
2つの画像の色分布の、同じ分布位置の数のうち、小さい方を選んでいって合計する、というのに一瞬あれ?と思ったのですが、色分布の合計は画像のピクセル数になるので、納得です。

作ったプログラムがこちらです。

common.php
create_mini_pic.php
create_resemble_pic.php

imagickとGD両方使っていたり、コマンドのエスケープをしていなかったり、エラー処理がなかったりしますが、目をつむる方向で。。。

ミニ画像を作るための画像は、会社の誕生日会や社員旅行の写真を使用しました。(約100枚)ミニ画像を作ってながめてみると、色に相当偏りがあります。オレンジや茶色の暖色系が多かったので、再現したい画像も同じような色合いのものを選びました。

できた画像がこちらです。



さて、これの元画像は何でしょう?

AS3のBitmapFilterを片っぱしから試してみる

こんにちは。松田です。
今年も早いものでいつの間にかエイプリルフールをむかえてしまったようですが、なんのネタも用意して無かったのでいたってふつうのブログです。
今回はActionScriptで画像処理をするには欠かせない、BitmapFilter類を試してみます。

今回はflash.filtersから以下のフィルターを試しています。


BevelFilter
BlurFilter
GlowFilter
DropShadowFilter
ColorMatrixFilter
ConvolutionFilter
DisplacementMapFilter


片っ端からとかいいながら全部のフィルターは試してないです。ごめなさい。
ちょっとだけ嘘つきました。
それぞれどんな効果があるのか、Adobeの解説ページを読むよりも実際に見てみた方が分かりやすいと思うので、実際に実装したswfを置いています。
ボタンをいろいろ押しまくって確認してみてください。



動かしてみるとそれぞれのフィルターの使い道が何となく分かるかと思います。
が、ColorMatrixFilter, ConvolutionFilter, DisplacementMapFilterあたりは使用方法が幅広く、使い方次第でいろんなことが出来てしまうフィルターです。
ですので、今回はその中から使い道を一つだけ選んで使用してます。

ソースコードは上のフラッシュ内で右クリックして「ソースの表示」を押してください。
一応下にも載せておきますが上記方法のほうが見やすいと思います。
こんなに簡単なコードでこれだけ多彩な画像処理が行えてしまうのもASの魅力ですね。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="330" height="300" creationComplete="init()" viewSourceURL="srcview/index.html">
  <mx:Canvas left="0" top="0" bottom="0" right="0" backgroundColor="gray">
	  <mx:Image id="image" source="@Embed(source='assets/image.png')"  x="10" y="10" />
	  <mx:Button x="10" y="146" label="もとにもどす" click="revertImage()"/>
	  <mx:Button x="10" y="176" label="Bevel" click="applyBevelFilter()"/>
	  <mx:Button x="76" y="176" label="Blur" click="applyBlurFilter()"/>
	  <mx:Button x="131" y="176" label="Glow" click="applyGlowFilter()"/>
	  <mx:Button x="192" y="176" label="DropShadow" click="applyDropShadowFilter()"/>
	  <mx:Button x="10" y="206" label="ColorMatrix (GrayScale変換)" click="applyColorMatrixFilter()"/>
	  <mx:Button x="10" y="236" label="Convolution (エッジ検出)" click="applyConvolutionFilter()"/>
	  <mx:Button x="10" y="268" label="DisplacementMap(波打ち)" click="applyDisplacementMapFilter()"/>
  </mx:Canvas>
  
  <mx:Script>
    <![CDATA[
      import flash.filters.*;
      
      // 表示されている画像のBitmapData
      private var bitmapData:BitmapData;
      
      // もともとの画像のBitmapData もとにもどす用
      private var baseBitmapData:BitmapData;
      
      /**
      * 初期設定
      */
			public function init():void 
      {
        // Imageオブジェクトに読み込んだ画像をBitmapDataに変換して変数に格納しておく
        // このbitmapDataを操作してImageに上書きすることでフィルターをかける
        // もとの画像より大きくなるフィルターもあるので大きめに作っておきますん
        this.bitmapData = new BitmapData(this.image.width + 50, this.image.height + 50, true, 0x000000);
        this.bitmapData.draw(this.image);
        
        // もとの画像に戻すために初期のBitmapDataを別に保存しておく
        this.baseBitmapData = new BitmapData(this.image.width + 50, this.image.height + 50, true, 0x000000);
        this.baseBitmapData.copyPixels(this.bitmapData, this.bitmapData.rect, new Point(0,0));
			}
      
      
      /**
      * もとに戻す
      * 初期のBitmapDataを現在のBitmapDataにコピーして上書き
      */ 
      private function revertImage():void
      {
        this.bitmapData.copyPixels(this.baseBitmapData, this.baseBitmapData.rect, new Point(0,0));
      }
      
      
      
      /**
      * BevelFilter
      * 
      * ベベル効果?日本語での用語はないのかな
      * 縁取りをして立体っぽく見せる効果
      */
      private function applyBevelFilter():void
      {
        var filter:BevelFilter = new BevelFilter();
        
        this.applyFilterToImage(filter);
      }
      
       
      /**
      * BlurFilter
      * 
      * 画像をぼかす
      */
      private function applyBlurFilter():void
      {
        var filter:BlurFilter = new BlurFilter();
        
        this.applyFilterToImage(filter);
      }
       
      
      /**
      * GlowFilter
      * 
      * 縁取りをして光らせたりする
      */
      private function applyGlowFilter():void
      {
        var filter:GlowFilter = new GlowFilter(0xFFFFFF, 1, 10, 10, 5, 3, true, false);
        
        this.applyFilterToImage(filter);
      }
       
      
      /**
      * DropShadowFilter
      * 
      * 画像に影をつける
      */
      private function applyDropShadowFilter():void 
      {
        var filter:DropShadowFilter = new DropShadowFilter(20);
        
        this.applyFilterToImage(filter);
      }
      
      
      /**
      * ColorMatrixFilter
      * 
      * 画像のRGB+Alpha値をマトリクスを使って変換する
      * 今回はこれを使ってグレースケールに変換
      * 
      * ここの解説が分かりやすい
      * http://d.hatena.ne.jp/umezo/20090122/1232627694
      */
      private function applyColorMatrixFilter():void
      {
        var filter:ColorMatrixFilter = new ColorMatrixFilter([
          1/3, 1/3, 1/3, 0, 0,
          1/3, 1/3, 1/3, 0, 0,
          1/3, 1/3, 1/3, 0, 0,
          1/3, 1/3, 1/3, 0, 0,
          0, 0, 0, 255, 0
        ]);
        
        this.applyFilterToImage(filter);
      }
      
      
      /**
      * ConvolutionFilter
      * 
      * 畳込みフィルタ
      * 配列で指定したフィルタリングを画像の各ピクセルに適用していく
      * ぼかし、エッジ検出、シャープ、エンボス、ベベル・・・とかがこれ1つで実現できるらしい
      * 
      * 下のコードは、対象のピクセルの周り8ピクセルを-1で弱めて、その分中心の1ピクセルを強調させてエッジ検出している例
      * 
      * 参照
      * http://www.imajuk.com/blog/archives/2009/02/convolutionflter.html
      */
      private function applyConvolutionFilter():void
      {
        var filter:ConvolutionFilter = new ConvolutionFilter(3, 3,
          [
            -1, -1, -1,
            -1, +8, -1,
            -1, -1, -1 
          ]
	      );
        
        this.applyFilterToImage(filter);
      }
      
       
      /**
      * DisplacementMapFilter
      * 
      * 置き換えフィルタ
      * 画像を波打たせたりぼかしたりできる
      * perlinNoise(ランダムな模様を生成する)と組み合わせて画像を波打たせる効果を作ることが多いらしい
      * 
	    * perlinNoiseについてはここを参照
	    * http://d.hatena.ne.jp/kkanda/20080224/p1
      * 
      * DisplacementMapFilterについてはこちらを参照
      * http://d.hatena.ne.jp/kkanda/20080305/p1
      * http://endlessblank.com/blog/2009/06/displacementmapfilter.html
      */
      private function applyDisplacementMapFilter():void
      {
        // ランダムな縞模様を生成
        var perlinNoiseBitmap:BitmapData = new BitmapData(this.bitmapData.width, this.bitmapData.height);
        perlinNoiseBitmap.perlinNoise(
          perlinNoiseBitmap.width, 
          perlinNoiseBitmap.height, 
          10, 
          Math.floor(Math.random() * 65535), 
          false, 
          true
        );
        
        // 生成したランダムな模様を利用して波打たせる
        var filter:DisplacementMapFilter = new DisplacementMapFilter(
          perlinNoiseBitmap,  // 変換の元となるBitmapData
          new Point(0, 0),    // 変換開始ポイント
          1, // x座標の変形に使用する色 1=red, 2=green, 3=blue, 4=alpha
          1, // y座標の変形に使用する色
          30,// x座標の乗数
          30 // y座標の乗数
        );
          
        this.applyFilterToImage(filter);
      }
      
      
      
      /**
      * ここで実際にフィルターをかける
      * 修正したBitmapDataをImageオブジェクトに反映させるには、
      * BitmapData を Bitmap オブジェクトに格納した後に Image.load(Bitmap) を使う
      */
      private function applyFilterToImage(filter:BitmapFilter):void 
      { 
        // フィルターかけて
        this.bitmapData.applyFilter(this.bitmapData, this.bitmapData.rect, new Point(0, 0), filter);
        
        // BitmapはBitmapDataを入れておく器
        var bitmap:Bitmap = new Bitmap(this.bitmapData);
        
        // ここでImageに反映!
        this.image.load(bitmap);
      }
      
    ]]>
  </mx:Script>
</mx:Application>




参考にさせて頂いたURL
* http://d.hatena.ne.jp/umezo/20090122/1232627694
* http://www.imajuk.com/blog/archives/2009/02/convolutionflter.html
* http://d.hatena.ne.jp/kkanda/20080224/p1
* http://d.hatena.ne.jp/kkanda/20080305/p1
* http://endlessblank.com/blog/2009/06/displacementmapfilter.html

BitmapData.thresholdで画像の特定の色を変える

こんにちは。最近Flexばかりいじっている松田です。今日もFlexネタです。
今回は、与えられた画像の特定のエリアをハイライトさせるスクリプトを作ってみました。
正確にはマウスオーバーしたピクセルと同じ色のエリアのハイライトをしています。

画像の読み込みには大抵の場合Loaderを使用しますが、Loaderで画像を読み込むと画像がBitmap型に変換されてLoader.contentに入ります。
このBitmapは画像データのただの器のようなもので、画像自体に手を加えるには、Bitmap.bitmapDataをイジることになります。
BitmapDataには画像処理を行ううえで便利なメソッドが多く用意されていますが、その中から今回はthresholdメソッドを使ってます。

おおまかな流れは以下のとおり。


1. 画像の取得、配置
↓
2. マウスカーソル位置の画像の色を取得
↓
3. 画像内のその色の部分を違う色に置き換えて表示
↓
4. マウスが違う色の上に移動したら元の画像に置き換える


3番の色を変更させる部分にBitmapData.thresholdを使用してます。
thresholdは直訳すると「しきい値」。与えられたBitmapDataに色の閾値と判定条件('<=', '==', '>=', ...) を与え、その条件に一致した部分の色を指定した色に置き換えるメソッドです。





bitmapData.threshold(bitmapData, bitmapData.rect, new Point(0,0), '==', thresholdColor, replaceColor, 0xFFFFFF);

上記のように指定した場合、


if ((各ピクセルの色  & 0xFFFFFF) == (thresholdColor  & 0xFFFFFF)) {
  各ピクセルの色を replaceColor に変更
}

こんな処理になります。
実際はもう一つ引数があるけど今回は無視。


使用した画像がこれ。


そして下に表示されているのが作成したFlashです。

Flash上で右クリック→「ソースの表示」でソースコードが表示できます。


ほんとは色を変えたエリアの周りをピカっと光らせたいけど、やりかたがわかりません・・・。

GDとImageMagickの画質比較

こんばんは、牧野です。
以前、GDでの画像処理を紹介しました。
今日はPHPでよく使われるもう1つの画像処理方法、ImageMagickを使うやり方で画質にどれくらい差があるのか比べてみました。

まずは早速、テスト用プログラムです。

gd_test.php


<?php
$image_file = 'sample.jpg';

$img = new MyImage($image_file);
$img->resizeImage(500, 500);
$img->createImageFile('.', 'gd_sample.jpg');

header('Content-type: image/jpeg');
readfile('gd_sample.jpg');

class MyImage {
    var $img;
    var $width;
    var $height;
    var $font_path;

    function MyImage($image_path, $font_file_path = null) {
        $this->img = imagecreatefromjpeg($image_path);
        $this->width = imagesx($this->img);
        $this->height = imagesy($this->img);
    }

    function resizeImage($max_w, $max_h) {
        if (floatval($max_w / $this->width - 1) <= floatval($max_h / $this->height - 1)) {
            $rate = floatval($max_w / $this->width);
            $new_w = $max_w;
            $new_h = (int)min(intval($this->height * $rate), $max_h);
        } else {
            $rate = floatval($max_h / $this->height);
            $new_w = (int)min(intval($this->width * $rate), $max_w);
            $new_h = $max_h;
        }
        $new_img = imagecreatetruecolor($new_w, $new_h);

        if (imagecopyresampled($new_img, $this->img, 0, 0, 0, 0, $new_w, $new_h, $this->width, $this->height)) {
            $this->img = $new_img;
            return true;

        } else {
            return false;
        }
    }

    function createImageFile($new_file_dir, $new_file_name) {
        $new_file_path = $new_file_dir .'/'. $new_file_name;
        $result = imagejpeg($this->img, $new_file_path, 100);
        chmod($new_file_path, 0666);
        return $result;
    }
}


imagick_test.php


<?php
$image_file = 'sample.jpg';

$img = new MyImage($image_file);

header('Content-type: image/jpeg');
echo $img->createResizedImage(500, 500);

class MyImage {
    var $img_path;
    var $width;
    var $height;
    var $font_file_path;

    function MyImage($image_path) {
        $this->img_path = $image_path;
        $image_info = getimagesize($this->img_path);
        $this->width = $image_info[0];
        $this->height = $image_info[1];
    }

    function createResizedImage($max_w, $max_h, $new_file_dir = null, $new_file_name = null) {
        if ($new_file_name) {
            $new_file_path = $new_file_dir .'/'. $new_file_name;
            $cmd = "convert ". $this->img_path ." -resize {$max_w}x{$max_h} {$new_file_path} ";
            system($cmd);
        } else {
            $cmd = "convert ". $this->img_path ." -resize {$max_w}x{$max_h} -";
            return shell_exec($cmd);
        }
    }

}


GDの場合、以前笹亀さんが書いていたように、サムネイル画像サイズを自力で計算する必要があります。
ImageMagickpeclエクステンションもありますが、サーバにインストールされているImageMagickPHPのバージョンの制限がわりと厳しいので、コマンドラインから使う方が手軽だと思います。

今回比べたかったのは画質なので、それ以外のことはとりあえず無視します。
(プログラムの書き方がいい加減というつっこみは今回はできればなしの方向で。。。)
画像をアップロードして、それを適当な大きさの表示用画像とサムネイル画像にサイズ変更して保存する、という機能は、ウェブアプリケーションでは比較的よくある機能だと思います。その時にどれくらい差が出るものなのかを調べるのが今回の目的です。
元画像のsample.jpgは、615×410で、今回のテストでは少しだけ小さくしています。

結果は、、

GDで変換した画像



ImageMagickで変換した画像


元画像はこちら

ブログの写真では変わらないように見えるかもしれませんが、ImageMagickを使ったほうがピントが合っているような感じで少し綺麗でした。
ということで、ImageMagickの方が画質的にはいいということがわかりました。

GD、ImageMagickともに様々な関数、オプションが用意されています。
GDでもこの関数をこんなふうにするともっと綺麗になる、等、何かご存知の方がいましたら、ぜひお知らせ下さい。

ImageMagickでいろいろなサムネイル画像作成に挑戦

最近、MacBook AirではなくてMacBookを購入してMac生活をエンジョイ中の笹亀です。
長年使用していたWindowsからの乗り換えのため、非常に慣れない日々を過ごしてきましたが、徐々にMacの環境にも慣れてきました^^

さて、PHPで画像処理を行うといえば、GDライブラリが有名です。
GDでも画像に対して処理を加えてサムネイルなどの作成が容易に行えます。
その他にも、PHPのエクステンションとして「imagick」という画像ライブラリも用意されており、画像処理に関しては結構充実しております。

今回は、GDやimagickをPHPから使用するのではなくImageMagickをCL(コマンドライン)で操作して様々な画像の処理を行ってみたいと思います。
画像の処理を行うImageMagickのコマンドはたくさんありますが、今回は「convert」コマンドのみを使用して作成していきます。

まずは基本的な使用方法です。

■フォーマットの変換
画像のフォーマットを変換できます。
拡張子から画像のフォーマットを判別して、jpgファイルをpngファイルにフォーマットを変換しています。


convert pa_01.jpg pa_01.png


■画像サイズの変換方法
resizeオプションとサイズを指定して画像サイズを変更することができます。
縦横比は自動的に適切な比率で調整してくれるのが特徴です。


convert pa_01.jpg -resize 200x200 pa_01_resize.jpg



サイズの後ろに「!」を付けると、縦横比は無視してサイズ変換されます。


convert pa_01.jpg -resize 300x200! pa_01_resize1.jpg



自動調整をしてくれるのを知らないで、自分が実装したときには自前でリサイズのサイズを求めてサムネイルを作成していました;;

■最大色数の指定方法
colorsオプションで最大色数を指定できます。


convert pa_01.jpg -colors 50 -resize 200x200 pa_01_resize.jpg


通常、サイズが小さくなるとおもったのですが、今回試した場合は逆にサイズが増えました。
原因はなぞです。。
colorオプション指定なしの200x200:約15kb
colorオプション指定ありの200x200:約20kb

■アニメーションGIF作成
複数の画像を指定してアニメーションGIFを作成することができます。


convert -delay 100 pa_*_resize.jpg pa.gif


delayオプションを使用して画像の切り替え時間を指定します。
今回は100(1秒)ごとに切り替えるように設定しました。

※クリックするとアニメーションを確認できます。

■アニメーションGIFをリサイズする方法
アニメーションGIFのリサイズをきれいに行うことができます。
アニメーションの構成枚数が多い場合は画像サイズが大きくなってしまうのが弱点です。


convert pa.gif -coalesce -resize 100x100 -deconstruct pa_small.gif
coalesce:オプションは画像シーケンスをマージ
deconstruct:オプションは画像シーケンス要素ごとに分解


※クリックするとアニメーションを確認できます。

上記のまでのことが基本的によく使う方法になります。
そんな中で、私がよく使用する方法として下記の2つをご紹介します。

アニメーションGIFをリサイズするのはサイズが大きくなってしまい、
携帯サイトの場合だとあまり不向きなため、アニメーションの最初の画像をリサイズする方法を使用していました。アニメーションGIFの最初の画像を指定して1枚の画像のみをリサイズする方法を使用します。実行方法は下記のように行います。


convert pa.gif[0] -resize 300x300 pa_03_resize.jpg

[0]のようにシーケンス番号を指定でき、特定のアニメーションGIFの画像をリサイズできます。


さらにこのようなことも行いました。
特定の枠の画像(背景色を白)を作成して、リサイズした画像を重ねるなどの方法です。
用途は、小さい画像でもデザインを崩さないように固定枠をもうけることにより、検索などのサムネイル画像に使用できます。


convert pa_01.jpg -resize 100x100 -size 150x150 xc:red +swap -gravity center -composite pa_04_resize.jpg

今回は結果をわかりやすくするために、150x150の赤い枠を作成して、100x100でリサイズした画像を真ん中に貼付けています。
「+swap」「-composite」はImageMagickのバージョンが古いと使用できない場合がありますので注意してください。私の環境では(6.2.8)では使用できました。


このように、ImageMagickは便利でいろいろな画像処理を行うことができます。
PHPのGDライブラリで画像処理を行うより、多くのことが行えるはずです。
ひとつ残念なことは、英語のマニュアルがメインなので詳しいオプションがわかりにくいというところでしょうか。

偶然かわかりませんが、最近「imagick」エクステンションもバージョンアップされたので、この機会にぜひ、ImageMagickで画像処理を試してみてはいかがでしょうか。

Seam Carvingで自然に画像をリサイズするPHPエクステンション

以前に紹介したSeam Carvingという技術を使用したプログラムをPHPエクステンションで実装してみました。
実験的なものなのでご利用は自己責任でお願いします。

少し前の話題となってしまいますが、Seam Carvingを使用した画像のリサイズが話題になりました。
オンラインサービスでresizrというものまで出てきているようです。

ロジック自体は単純なので割とすぐにPHPで実装できたのですが、パフォーマンスが最悪だったのです。
そこで、PHPエクステンションなら何となるかなと思いトライしてみました。

seam_carving.tar.gz
cocoiti さんの指摘を修正しました。ご指摘ありがとうございます!

以下のように画像を縮小することができます。

元画像(1024×768)


768×768
かなりスムーズなリサイズです。


512×768
半分になっても意外と大丈夫ですね。


256×768
さすがに4分の1にまで縮小すると汚くなってしまいます。



エクステンション自体のインストールはtar.gzを解凍して、phpize、configure、make とします。



$ tar xzf seam_carving.tar.gz
$ cd seam_carving
$ phpize
$ ./configure
$ make


modulesディレクトリにseam_carving.soができあがるので make install でインストールするなり、どこかのディレクトリにおいておきます。

準備ができたら、以下のようにしてリサイズします。



<?php

dl('seam_carving.so');

$im = imagecreatefromjpeg('Antelope.jpg');
$new_im = seam_imagecreate($im, 100);



画像のリサイズは seam_imagecreate関数で実行します。第1引数がGDの画像リソースで、第2引数が横方向にカットするピクセル数です。

マシンスペックにもよると思いますが、1024×768の画像を1秒で10ピクセルくらいずつカットすることができました。

これでもずいぶんとPHPプログラムでの実装よりは高速になっています。エクステンションのコードを修正すれば、まだまだ高速化できると思います。

まだまだエクステンションの書き方がわかっていないので、エラー処理ができていません。異常終了したりするかもしれません。。
そこら辺は多めに見てください^^;

CodeGen_Peclで四苦八苦

森川です。

この間のSeam CarvingのPHPソースコードはあまりにも遅かったので、PHPエクステンションで作ってみることにしました。

PHPエクステンションといえばCodeGen_Pecl、ということで勉強がてら作ってみることにしました。

まずは、Do You PHPにあるとおりにHello Worldの作成です。ここまでは割とすいすい、簡単にできます。

が、しかしなのです。PHPのGDライブラリをどうやって使うのか、GDのリソースはどうやって使うのか、さっぱりわかりません。。。

と思って、いろいろと探してみると、ずばりなものがありました。

讃容日記というところで、gdextraというエクステンションが公開されており、うってつけの勉強材料!

まずは、PHPのモジュール依存の定義からです。



<deps language="c" platform="all">
  <extension name="gd" />
  <with>
    <header name="ext/gd/libgd/gd.h" />
  </with>
</deps>


こんな感じで、gdモジュールとPHP組み込みのgdライブラリのヘッダファイルの依存を定義することができます。こうしておけば、自動的にgdライブラリのヘッダファイルも読み込まれます。

これで、スクリプトを書く準備が整いましたが、肝心のリソースを使用することができません。リソースを使用するには、リソースの番号のようなものが必要なのでした。

この番号はgdモジュールのソースコードでは、static int le_gdのように定義されているのですが、当然le_gdは今作成しているモジュールからは参照することができません。

そのため、phpi_get_le_gd()という関数が用意されており、画像リソースの番号を取得することができます。

とりあえず、imagecreatetruecolorの丸々コピーのような関数は以下のXMLpecl-genで指定すると作成できます。



<?xml version="1.0"?>
<extension name="seamcarving" version="1.0.0">
  <summary>Seam Carving</summary>
  <description>
This is a expanding or contracting image extension.
  </description>
  <license>PHP</license>
  <maintainers>
    <maintainer>
      <user>joe</user>
      <name>MORIKAWA Joe</name>
      <role>lead</role>
    </maintainer>
  </maintainers>

  <release>
    <version>1.0.0</version>
    <date>2007-09-13</date>
    <state>alpha</state>
    <notes> 
- My first PHP extension.
    </notes>
  </release>

  <deps language="c" platform="all">
    <extension name="gd" />
    <with>  
      <header name="ext/gd/libgd/gd.h" />
    </with> 
  </deps> 

  <function name="seam_imagecreate">
    <proto>resource seam_imagecreate(int x_size, int y_size)</proto>
    <code><![CDATA[
gdImagePtr im;

if (x_size <= 0 || y_size <= 0) {
  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid image dimensions");
  RETURN_FALSE;
}

im = gdImageCreateTrueColor(x_size, y_size);

ZEND_REGISTER_RESOURCE(return_value, im, phpi_get_le_gd());
    ]]></code>
  </function>
</extension>


ここまで来れば、あともう少しで実際のSeam Carvingエクステンションを作成できそうです。

次回をお楽しみに!

#ちゃんとしたものになったらAjax版で公開したいなぁ。。

久々の趣味プログラミング

森川です。

今回は秋元さんのブログをみて興味がわき、休日に趣味プログラムしてみました。

題材は、話題?のSeam Carvingです。あまり時間もとれなかったので、論文の最初に出てくるseamの削除しかやっていません。というかそれ以上のことを実装しようとすると、1日ではできません。。。

最初は難しいのかなと思ったのですが、意外や意外、すんごく簡単でした。でもPHPで実装したら、メモリ消費量がとんでもないので、実際の画面は公開できません。

せっかく実装したので、ソースコードだけアップロードします。

seam.php

energy functionをひょっとしたら勘違いしているかもしれません。中心のコンテンツが大部分を占めるような画像ではあまり綺麗にリサイズできません。それと人間の顔も変な風になります(本家のほうでは顔認識と組み合わせているようです)。

もっと効率的にできると思うのだけど、中々どうしてよいアルゴリズムが浮かびませんでした。。。

とりあえず、わりと高速なサーバを持っていれば1分以内には結果が返ってくると思います(メモリは100Mくらい消費します)。

Flashで実装している人もいるようなので、真似してみたい人はアルゴリズムの参考程度にしてみてください。