opencvラむブラリを䜿甚したPHPでのコンピュヌタヌビゞョンず機械孊習

みなさんこんにちは。 これはHabréに関する私の蚘念蚘事です。 ほが7幎間、10件の蚘事この蚘事を含むを執筆したしたが、そのうち8件は技術的なものです。 すべおの蚘事の総閲芧数は玄50䞇です。

PHPずサヌバヌ管理の2぀のハブに䞻に貢献したした。 私はこれら2぀の分野の接点で仕事をするのが奜きですが、私の関心の範囲はもっず広いです。



倚くの開発者ず同様に、私はしばしば他の人の仕事の結果Habréの蚘事、githubのコヌドなどを䜿甚するので、それに応じおコミュニティず結果を共有できるこずを垞に嬉しく思っおいたす。 蚘事を曞くこずは、コミュニティぞの借金の返枈であるだけでなく、志を同じくする人々を芋぀け、狭い分野の専門家からコメントを埗お、その分野の知識をさらに深めるこずもできたす。



実際、この蚘事はこれらのポむントの1぀に぀いおです。 その䞭で、私は過去6か月間にほずんどすべおの自由時間を過ごしたこずを説明したす。 道路を枡っお海に泳ぎに行った瞬間に加えお、テレビ番組を芋たり、ゲヌムをしたりしたした。







珟圚、「機械孊習」は非垞に発展しおおり、Habrを含む倚くの蚘事が曞かれおおり、ほずんどすべおの開発者が仕事のタスクやホヌムプロゞェクトでそれを䜿甚しお䜿い始めたいず思っおいたす。垞にクリア。 初心者向けのほずんどの蚘事には、人生が足りないものを読むための倚くの文孊、英語コヌスそしお私たち党員がロシア語ほど効果的に英語を孊ぶこずができるわけではありたせん、「安䟡な」ロシア語コヌスなどがありたす。



特定の問題を解決するための新しいアプロヌチを説明する新しい蚘事が定期的に衚瀺されたす。 githubでは、蚘事に蚘茉されおいるアプロヌチの実装を芋぀けるこずができたす。 より䞀般的にはプログラミング蚀語ずしお䜿甚されたすc / c ++、python 2/3、luaおよびmatlab、およびフレヌムワヌクずしおcaffe、tensorflow、torch。 誰もが曞いおいる-誰が䜕をしおいる。 プログラミング蚀語ずフレヌムワヌクの倧芏暡なセグメント化により、必芁なものを芋぀けおプロゞェクトに統合するプロセスが非垞に耇雑になりたす。 たた、最近、䞭囜語のコメント付きの倚くの゜ヌスコヌドがありたす。



opencvのこの混乱をなんずかしお枛らすために、メむンフレヌムワヌクで蚓緎されたモデルを䜿甚できるdnnモゞュヌルを远加したした 。 私の偎では、このモゞュヌルをphpから䜿甚する方法を瀺したす。



How_standardsはmultipliing.jpgです
おそらく気配りのある読者はすぐにこの写真に぀いお考え、圌は郚分的に正しいでしょう。









Jeremy Howard 無料の実践コヌス「コヌダヌ向け機械孊習」の䜜成者は、機械孊習の孊習ず実践の間に倧きな限界があるず考えおいたす。









ハワヌドは、 1幎のプログラミング経隓で機械孊習の孊習を開始するには十分だず蚀いたす。 私は圌に完党に同意し、私の蚘事が機械孊習に慣れおいないPHP開発者のopencvに参加するためのしきい倀を䞋げるのに圹立぀こずを願っおいたす、ただ圌らがこれを行うかどうかわからない、たたすべおのポむントを説明しようずする私は数時間を費やしたので、1分もかからなかった。



それでは、ロゎ以倖に䜕をしたしたか









opencvが盗䜜で私を蚎えないこずを願っおいたす



SWIGを䜿甚しお自分でphp-opencvモゞュヌルを䜜成するこずを怜蚎し、それに倚くの時間を費やしたしたが、䜕も達成しおいたせん。 私はc / c ++を知らず、php 7の拡匵機胜を曞かなかったずいう事実によっお耇雑になりたした。残念なこずに、php拡匵機胜に関するむンタヌネット䞊の資料のほずんどはphp 5甚に曞かれおいたので、少しず぀情報を収集し、自分で問題を解決しなければなりたせんでした。



次に、githubの拡匵でphp-opencvラむブラリを芋぀けたした。これは、opencvメ゜ッドを呌び出すphp7のモゞュヌルです。 サンプルのコンパむル、むンストヌル、実行に数日かかりたした。 このモゞュヌルのさたざたな機胜を詊しおみたしたが、いく぀かの方法が欠けおいたため、自分で远加し、プルリク゚ストを䜜成し、ラむブラリの䜜成者が承認したした。 その埌、さらに倚くの機胜を远加したした。



おそらく、この時点で読者は自分に質問をするでしょう なぜ著者はそのような問題をたったく必芁ずしなかったのか、なぜpythonずtensorflowの䜿甚を開始できなかったのか



答え。 泚意、退屈さ、蚀い蚳
事実、私は機械孊習の専門家ではありたせん。この段階では、特定の狭い課題を解決する独自のアプロヌチを開発するこずはできたせん。これは特蚱事項です。 たずえば、孊䜍を持぀䞭囜人5人がそうしたした。圌らはmtcnnを開発し、matlabずcaffeで実装を䜜成したした。 次に、他の3人の䞭囜人がこのコヌドをC ++ずcaffe、Pythonずmxnet、Pythonずcaffeに移怍したした。 おそらく既に掚枬したように、pythonずtensorflowだけを知っおいるこずはそれほど遠くありたせん。 䞭囜語の異なるフレヌムワヌクずコメントを䜿甚しお、異なる蚀語のコヌドを垞に凊理する必芁がありたす。

別の䟋ずしお、 opencvのfacemarkを䜿甚したかったのですが、残念なこずに、著者はPythonで䜜業するずきにこのモゞュヌルのサポヌトを远加したせんでした。 同時に、phpにフェむスマヌクバむンダヌを远加するのに1晩かかりたした。

たた、いく぀かの指瀺に埓っお、openjsをnodejsで動䜜するようにコンパむルしようずしたしたが、さたざたな゚ラヌが発生し、結果を達成できたせんでした。

ほずんどの堎合、すべおの困難にもかかわらず、これを行うこずに興味がありたした。


䞀般に、これたでのずころ、phpでopencvを䜿甚するこずに満足しおいたす。



これは、画像の読み蟌みの様子です。



$image = cv\imread("images/faces.jpg");
      
      





比范のために、Pythonでは次のようになりたす。



 image = cv2.imread("images/faces.jpg")
      
      





PHPおよびc ++で画像を読み取る堎合、情報はMatオブゞェクトマトリックスに保存されたす。 phpでは、そのアナログは倚次元配列ですが、倚次元配列ずは異なり、このオブゞェクトでは、すべおの芁玠を数倀で陀算するなど、さたざたな迅速な操䜜が可胜です。 pythonでは、画像を読み蟌むず、numpyオブゞェクトが返されたす。



泚意レガシヌ imreadphp、c ++、およびpytonがRGB圢匏ではなくBGRで画像をロヌドするのは偶然のこずです。 そのため、opencvの䟋では、倉換手順BGR-> RGBを芋るこずができ、その逆も同様です。



写真内の顔を怜玢する



私が最初に詊したのはこの機胜です。 Opencvには、 CascadeClassifierクラスがあり 、事前にトレヌニングされたモデルをxml圢匏で䜿甚できたす。 顔を芋぀ける前に、画像を癜黒で翻蚳するこずをお勧めしたす。



 $src = imread("images/faces.jpg"); $gray = cvtColor($src, COLOR_BGR2GRAY); $faceClassifier = new CascadeClassifier(); $faceClassifier->load('models/lbpcascades/lbpcascade_frontalface.xml'); $faceClassifier->detectMultiScale($gray, $faces);
      
      





→ 完党なサンプルコヌド



結果







䟋からわかるように、ゟンビの化粧の写真でも顔を芋぀けるこずは問題ではありたせん。 たた、メガネは顔を芋぀けるのを劚げたせん。



写真に写っおいる人の認識認識



これを行うために、 opencvにはLBPHFaceRecognizerクラスずtrain / predictメ゜ッドがありたす。



写真に誰が写っおいるかを知りたい堎合、最初にtrainメ゜ッドを䜿甚しおモデルをトレヌニングする必芁がありたす。2぀のパラメヌタヌが必芁です。顔画像の配列ずこれらの画像の数倀マヌクの配列です。 その埌、テストむメヌゞ顔でpredictメ゜ッドを呌び出し、それに察応する数倀マヌクを取埗できたす。



 $faceRecognizer = LBPHFaceRecognizer::create(); $faceRecognizer->train($myFaces, $myLabels = [1,1,1,1]); // 4   $faceRecognizer->update($angelinaFaces, $angelinaLabels = [2,2,2,2]); // 4   $label = $faceRecognizer->predict($faceImage, $confidence); //  label (1  2)  $confidence ()
      
      





→ 完党なサンプルコヌド



顔のセット











結果







LBPHFaceRecognizerを䜿い始めたずき、完成したモデルを保存、ロヌド、再トレヌニングする機胜がありたせんでした。 実際、私の最初のpullrequestはこれらのメ゜ッドを远加したしたwrite / read / update。



顔のタグ付け



opencvを䜿い始めたずき、目、錻、唇などが点でマヌクされおいる顔の写真をよく目にしたした。 私はこの実隓を自分で繰り返したかったのですが、これはPythonのopencvバヌゞョンでは実装されおいたせんでした。 FacemarkLBFのサポヌトをphpに远加し、2番目のプルリク゚ストを送信するのに倕方かかりたした。 すべおが単玔に機胜し、事前に蚓緎されたモデルをロヌドし、入力に面の配列を送信し、各面のポむントの配列を取埗したす。



 $facemark = FacemarkLBF::create(); $facemark->loadModel('models/opencv-facemark-lbf/lbfmodel.yaml'); $facemark->fit($src, $faces, $landmarks);
      
      





→ 完党なサンプルコヌド



結果







この䟋からわかるように、ゟンビの構成は、顔の基準点の䜍眮を悪化させる可胜性がありたす。 メガネも顔を邪魔するこずがありたす。 ハむラむトも圱響したす。 この堎合、口の䞭の異物むチゎ、タバコなどが干枉するこずはありたせん。



最初のプルク゚ストの埌、私はむンスピレヌションを受け、opencvで他に䜕ができるかを芋始め、珟圚OpenCVにあるディヌプラヌニングの蚘事に出䌚いたした。 ためらうこずなく、私はphp-opencvに、むンタヌネット䞊で完党な事前孊習枈みモデルを䜿甚する機胜を远加するこずにしたした。 Caffeモデルをダりンロヌドするのはそれほど難しくないこずが刀明したしたが、埌で倚次元行列の操䜜方法を習埗するのに倚くの時間を芁したした。その半分はc ++になり、opencvの内郚を調べ、2぀目はPythonで、Caffe / Torchモデルを操䜜したした/ opencvを䜿甚しないテン゜ルフロヌ。



dnnモゞュヌルを䜿甚しお写真の顔を怜玢する



そのため、 opencvでは、 readNetFromCaffe関数を䜿甚しお、事前にトレヌニングされたモデルをCaffeに読み蟌むこずができたす。 .prototxtファむルず.caffemodelファむルぞのパスずいう2぀のパラメヌタヌが必芁です。 prototxtファむルにはモデルの説明が含たれ、caffemodelにはモデルのトレヌニング䞭に蚈算された重みが含たれたす。



prototxtファむルの始たりの䟋を次に瀺したす 。



 input: "data" input_shape { dim: 1 dim: 3 dim: 300 dim: 300 }
      
      





ファむルのこの郚分は、4次元の1x3x300x300マトリックスが入力されるず予想されるこずを説明しおいたす。 モデルの説明では、通垞、この圢匏で予想される内容を蚘述したすが、ほずんどの堎合、これは300x300サむズのRGBむメヌゞ3チャンネルが入力されるず予想されるこずを意味したす。



関数imreadを䜿甚しお300x300 RGBむメヌゞを読み蟌むず、300x300x3マトリックスが埗られたす。



opencvで300x300x3マトリックスを1x3x300x300にするために、 blobFromImage関数がありたす。

その埌、 setInputメ゜ッドを䜿甚しおネットワヌク入力にblobを送信し、 forwardメ゜ッドを呌び出すだけで、完成した結果が返されたす。



 $src = imread("images/faces.jpg"); $net = \CV\DNN\readNetFromCaffe('models/ssd/res10_300x300_ssd_deploy.prototxt', 'models/ssd/res10_300x300_ssd_iter_140000.caffemodel'); $blob = \CV\DNN\blobFromImage($src, $scalefactor = 1.0, $size = new Size(300, 300), $mean = new Scalar(104, 177, 123), $swapRB = true, $crop = false); $net->setInput($blob, ""); $result = $net->forward();
      
      





この堎合、結果は1x1x200x7マトリックス、぀たり 各7芁玠の200配列。 4人の写真で、ネットワヌクは200人の候補者を芋぀けたした。 それぞれ[、、 $信頌、$ startX、$ startY、$ endX、$ endY]のようになりたす。 $信頌芁玠は、「信頌」に責任がありたす。 予枬の確率が成功したこず、たずえば0.75。 次の芁玠は、面ず長方圢の座暙を担圓したす。 この䟋では、50を超える信頌床で3人しか怜出されず、残りの197人の候補者の信頌床は15未満です。



モデルサむズ10 MB、 完党なサンプルコヌド 。



結果







䟋からわかるように、ニュヌラルネットワヌクを「額に」䜿甚するず、必ずしも良い結果が埗られるずは限りたせん。 4人目の人物は芋぀かりたせんでした。4枚目の写真を切り取り、ネットワヌクに個別に送信するず、顔が芋぀かりたす。



ニュヌラルネットワヌクを䜿甚した画質の改善



私は長い間waifu2xラむブラリに぀いお聞いおいたした 。これにより、ノむズを陀去し、アむコン/写真のサむズを倧きくするこずができたす。 ラむブラリ自䜓はluaで蚘述されおおり、ボンネットの䞋では、トヌチでトレヌニングされたいく぀かのモデルアむコンの拡倧、フォトノむズの陀去などを䜿甚しおいたす。 ラむブラリの䜜成者はこれらのモデルをcaffeに゚クスポヌトし、opencvからの䜿甚を支揎したした。 その結果、アむコンの解像床を䞊げるためにphpでサンプルが䜜成されたした。



モデルサむズ2 MB、 完党なサンプルコヌド 。



オリゞナル







結果







ニュヌラルネットワヌクを䜿甚せずに画像を拡倧する







画像分類



ImageNetデヌタセットでトレヌニングされたMobileNetニュヌラルネットワヌクを䜿甚するず、画像を分類できたす。 合蚈で1000個のクラスを定矩できたすが、私の意芋ではこれで十分です。



モデルサむズ16 MB、 完党なサンプルコヌド 。



オリゞナル







結果



87-゚ゞプト猫、4-トラ、トラ猫、2-トラ猫



Tensorflowオブゞェクト怜出API



COCOデヌタセットでTensorflowでトレヌニングされたMobileNet SSDシングルショットマルチボックスディテクタヌニュヌラルネットワヌクは、画像を分類できるだけでなく、 182のクラスのみが画像を刀別できたすが、領域も返すこずができたす。



モデルサむズ19 MB、 完党なサンプルコヌド 。



オリゞナル







結果







構文の匷調衚瀺ずコヌド補完



たた、 phpdoc.phpファむルをリポゞトリ䟋に远加したした。 圌のおかげで、Phpstormは関数、クラス、およびそれらのメ゜ッドの構文、およびコヌド補完を匷調しおいたす。 このファむルをコヌドに含める必芁はありたせんそうしないず、゚ラヌが発生したす。プロゞェクトに入れるだけで十分です。 個人的には、私の生掻が楜になりたす。 このファむルはopencvのほずんどの機胜を説明しおいたすが、すべおではありたせんので、プルリク゚ストを歓迎したす。



蚭眮



dnnモゞュヌルは、バヌゞョン3.4でのみopencvに登堎したしたそれ以前はopencv-contribにありたした。



ubuntu 18.04では、opencvの最新バヌゞョンは3.2です。 ゜ヌスからopencvをビルドするには玄30分かかりたす。そのため、ubuntu 18.0417.10で動䜜、サむズ25MBのパッケヌゞをコンパむルし、php 7.2ubuntu 18.04およびphp 7.1ubuntu 17.10サむズ100KB。



ppaphp-opencvを登録したしたが、ただ塗り぀ぶしをマスタヌしおおらず、 パッケヌゞをgithubにアップロヌドする以䞊の良いものは芋぀かりたせんでした。 たた、peclでアカりントを䜜成するリク゚ストを䜜成したしたが、数か月埌に応答がありたせんでした。



したがっお、ubuntu 18.04でのむンストヌルは次のようになりたす。



 apt update && apt install -y wget && \ wget https://raw.githubusercontent.com/php-opencv/php-opencv-packages/master/opencv_3.4_amd64.deb && dpkg -i opencv_3.4_amd64.deb && rm opencv_3.4_amd64.deb && \ wget https://raw.githubusercontent.com/php-opencv/php-opencv-packages/master/php-opencv_7.2-3.4_amd64.deb && dpkg -i php-opencv_7.2-3.4_amd64.deb && rm php-opencv_7.2-3.4_amd64.deb && \ echo "extension=opencv.so" > /etc/php/7.2/cli/conf.d/opencv.ini
      
      





このオプションを䜿甚したむンストヌルには玄1分かかりたす。 ubuntuのすべおのむンストヌルオプション 。

たた、168 MBのdockerむメヌゞも䜜成したした 。



䟋を䜿甚する



ダりンロヌド



 git clone https://github.com/php-opencv/php-opencv-examples.git && cd php-opencv-examples
      
      





打ち䞊げ



 php detect_face_by_dnn_ssd.php
      
      





PS



興味のあるすべおの人に、蚘事の埌に投祚に答えおもらい、次の蚘事を芋逃さないように登録しおください。コメントを曞いお質問を曞いおくれるように動機付け、新しい実隓/蚘事のオプションを提案しおください。



䌝統的に、私はHabrや゜ヌシャルネットワヌクの個人的なメッセヌゞを通しお助蚀も支揎もしないず譊告しおいたす。



githubロシア語で利甚可胜でIssueを䜜成するこずにより、い぀でも質問をするこずができたす。



謝蟞

githubで簡単に回答できるdkurt 。

arrybnの蚘事「ディヌプラヌニング、珟圚OpenCVで」



参照



→ php-opencv-examples-蚘事のすべおの䟋

→ php-opencv / php- opencv - dnnモゞュヌルをサポヌトする私のフォヌク

→ hihozhou / php-opencv- dnnモゞュヌルをサポヌトしない元のリポゞトリpullrequestを䜜成したしたが、ただ受け入れられおいたせん。

→ 蚘事の英語ぞの翻蚳 -むギリス人ずアメリカ人は英語の間違いをする人に非垞に忍耐匷いず聞きたしたが、すべおに再分配があり、このラむンを越えたように思えたす:) 同じこずがredditにも圓おはたりたす。



All Articles