Tesseract.js Javascript OCR文字認識

Canvas から切り抜いた画像でもって、OCRする必要あり、過去にtesseract を使ってサーバー側で処理した結果を応答する仕様のをリリースしたことがあり、今回もそれで行こうと思いましたが、
ちょっと調べたところ、何と、tesseract が Javascript で実行できるようになって、早速、利用してみました。

ここで教えて頂く : https://qiita.com/furunfuru/items/0ecf0a21273ae93bc060

< コード例 >


<script src='https://cdn.rawgit.com/naptha/tesseract.js/0.2.0/dist/tesseract.js'></script>


       // @@ 文字認識ボタンを押した時 @@ //
        $("#execocr").on("click", function (e) {

          //var img = $("#RecCanvas").toDataURL();
          // var img = document.getElementById("RecCanvas").toDataURL();
          var img = document.getElementById("RecCanvas").toDataURL("image/jpeg");

          Tesseract.recognize(img, {lang: "eng"}).then(function (result) {
            //const a = document.querySelector("#test");
            console.log(result);
            $("#ocrres").val(result.text);
          });
         });

< 対象画像 結果例 >

PHP GD 画像切り抜き

< コード例 >


<?php

/**
 * GD 画像 切り抜き
 * argv : 1:元ファイル名, 2:生成ファイル名, 3: 左上X座標, 4: 左上Y座標, 5:幅, 6:高さ  
 */
 
// 引数取得 //
$srcfnm = $argv[1];
$newfnm = $argv[2];
$sx = $argv[3];
$sy = $argv[4];
$w = $argv[5];
$h = $argv[6];

// 元画像サイズ取得 //
list($src_width, $src_height, $type) = getimagesize($srcfnm);

// 対象イメージ格納 //
switch ($type) {
  case IMAGETYPE_JPEG:    // 2
    $srcimg = imagecreatefromjpeg($srcfnm);
    break;
  case IMAGETYPE_PNG:     // 3
    $srcimg = imagecreatefrompng($srcfnm);
    break;
  case IMAGETYPE_GIF:     // 1
    $srcimg = imagecreatefromgif($srcfnm);
    break;
}

// 矩形指定
$rect = array();
$rect['x'] = $sx;
$rect['y'] = $sy;
$rect['width'] = $w;
$rect['height'] = $h;

// 画像を切り抜き
//$im_in = $func_create($srcfnm);
$im_out = imagecrop($srcimg, $rect);

// 結果ファイルに出力 //
$filepath = pathinfo($newfnm);
$ext = mb_strtolower($filepath['extension']);
$res = 1;
try {
  if ($ext === "jpg" || $ext === "jpeg") {
    imagejpeg($im_out, $newfnm, 100);
  }
  else if ($ext === "png") {
    imagepng($im_out, $newfnm, 9);
  }
  else if ($ext === "gif") {
    imagegif($im_out, $newfnm, 100);
  }
}
catch (Exception $ex) {
  $res = 0;
}

// 解放 //
imagedestroy($srcimg);
imagedestroy($im_out);

// 連想配列に格納 //
$responce = [];
$responce["Result"] = $res;

// JSONに変換して結果出力 //
echo json_encode($responce);


?>


[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

独習PHP 第4版 [ 山田 祥寛 ]
価格:3740円(税込、送料無料) (2022/12/26時点)

コマンドラインで バーコード画像認識 ZBarImg

必要に迫られ、画像ファイルからのバーコード認識ライブラリを探してました。

アプリケーションがJavaでWEBなので、AndroidでないJavaSE の API がふさわしいかと思い、

Zxing を調べてましたが、日本語情報少なく、StaackOverflowの投稿も、Android + QRコードが主、JavaのImageI/Oの記述がややこしく、Java8でエラー多発、未解決のとらうまもあり、

Zxing : https://github.com/zxing/zxing

ImageMagick のようにコマンド1行で目的達成したいので、さらに調べた結果、

ずばりなの見つけて、早速、組み込みました。

ZBarImg で出来ました。

ZBarImg 本家Home : http://zbar.sourceforge.net/

< 利用例 >

オプションなしで EAN13 が読めました。

< Windows >

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\2.png
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\2.jpg
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images


< Linux >

[root@???? zbarimg]# zbarimg 1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 2.png
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 2.jpg
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images in 0 seconds

< 対象画像 >

Cancvsで切り抜き => Base64にエンコードしてアップロード => サーバーで保存

< コード例 >

JavaScript


        // @@ バーコード認識ボタンを押した時 @@ //
        $("#execbarcd").on("click", function (e) {

          // 切り抜き画像 //
          var canvasData = $("#RecCanvas").get(0).toDataURL("");

          // 不要な情報を取り除く
          canvasData = canvasData.replace(/^data:image\/png;base64,/, "");

          var data = {};
          data.file = canvasData;

          // アップロード //
          $.ajax({
            url: 'BarcodeRecog${LW}',
            type: 'POST',
            data: data,
            dataType: 'text',
            success: function (txt) {
              simpleDialog2($("#alertdialog"), "Result", txt, "Close");
              $("#ocrres").val(txt);
            },
            error(jqXHR, textStatus, errorThrown) {
              simpleDialog2($("#alertdialog"), "ERROR", textStatus, "Close");
            },

          });

        });

Javaサーブレット


    String b64txt = request.getParameter("file");

    StringBuffer buf = new StringBuffer();
    try {

      // 時刻文字列 //
      String nowTMSeqStr
              = DateFormatUtils.format(new Date(), "yyyyMMdd_HHmmssSSS");

      // 画像ファイルを保存 //
      byte[] decode = Base64.getDecoder().decode(b64txt);
      String fnm = fileLocationPath + nowTMSeqStr + ".jpg";
      Path path = Paths.get(fnm);
      Files.write(path, decode);
      
      // zbarimgでバーコード取得 //
      String cmd = "c:\\ZBar\\bin\\zbarimg " + fnm;      
      System.out.println(cmd);
      RuntimeExec RE = new RuntimeExec(cmd, 500);
      RE.exec();
      
      // 別クラスにあるRuntimeexecで実行 //
      String restxt = RE.getRestxt();
      String resjan = restxt.substring(restxt.indexOf(":") + 1);
      buf.append(resjan);

    }
    catch (Exception e) {
      e.printStackTrace();
      buf.append(this.FAIL_MESSAGE);
    }

MySQL || で SELECT列の連結

他のデータベースからの移行で、MySQLのSELECT列連結で || が使えないものかと思い、調べてると方法がわかりました。

sql_mode に、PIPES_AS_CONCAT を加えると出来ます。

[ my.cnf 例 ]

sql_mode='NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT'

[ SELECT結果例 ]

mysql> select concat(host,user,plugin) from mysql.user where user = 'root' and host = 'localhost';
+------------------------------------+
| concat(host,user,plugin)           |
+------------------------------------+
| localhostrootmysql_native_password |
+------------------------------------+
1 row in set (0.00 sec)

mysql> select host || user || plugin from mysql.user where user = 'root' and host = 'localhost';
+------------------------------------+
| host || user || plugin             |
+------------------------------------+
| localhostrootmysql_native_password |
+------------------------------------+
1 row in set (0.00 sec)

ここで教えていただきました : http://proengineer.internous.co.jp/content/columnfeature/6836#section200

PHP GD 画像ファイル合成

[ コード例 ]


<?php

/**
 * GD 合成位置指定画像ファイル合成 
 * argv : 1:ファイル名A(背景), 2:ファイル名B(パネル), 3:生成ファイル名, 
 *        4:合成位置 (N, NE, E, SE, S, SW, W, NW, C), 5:パッディング (オプション) 
 */

// 引数取得 //
$fnm_a = $argv[1];
$fnm_b = $argv[2];
$fnm_new = $argv[3];
$mrglocation = $argv[4];
$PADDING = isset($argv[5]) ? $argv[5] : 12;   // 指定がない場合は12ピクセル

// Linux 引数の" が認識されてない対策 //
$fnm_a = str_replace("^", " ", $fnm_a);
$fnm_b = str_replace("^", " ", $fnm_b);
$fnm_new = str_replace("^", " ", $fnm_new);

// A, B画像サイズ, 画像タイプ取得 //
list($a_width, $a_height, $type_a) = getimagesize($fnm_a);
list($b_width, $b_height, $type_b) = getimagesize($fnm_b);

// 対象イメージ格納 //
switch ($type_a) {
  case IMAGETYPE_JPEG:    // 2
    $image_a = imagecreatefromjpeg($fnm_a);
    break;
  case IMAGETYPE_PNG:     // 3
    $image_a = imagecreatefrompng($fnm_a);
    break;
  case IMAGETYPE_GIF:     // 1
    $image_a = imagecreatefromgif($fnm_a);
    break;
}
switch ($type_b) {
  case IMAGETYPE_JPEG:    // 2
    $image_b = imagecreatefromjpeg($fnm_b);
    break;
  case IMAGETYPE_PNG:     // 3
    $image_b = imagecreatefrompng($fnm_b);
    break;
  case IMAGETYPE_GIF:     // 1
    $image_b = imagecreatefromgif($fnm_b);
    break;
}

// コピー先の画像,コピー元の画像,コピー先のx座標,コピー先のy座標,コピー元のx座標,コピー元のy座標,コピー元の幅,コピー元の高さ //
// 合成する //
switch ($mrglocation) {
  case "NW":   // 左上
    imagecopy($image_a, $image_b, $PADDING, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "NE":   // 右上
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "SE":   // 右下
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "SW":   // 左下
    imagecopy($image_a, $image_b, 12, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;

  case "N":    // 上中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "S":    // 下中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "E":    // 右中央
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $a_height / 2 - $PADDING / 2, 0, 0, $b_width, $b_height);
    break;
  case "W":    // 左中央
    imagecopy($image_a, $image_b, $PADDING, $a_height / 2 - $PADDING / 2, 0, 0, $b_width, $b_height);
    break;
  case "C":    // 中央中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $a_height / 2 - $b_height / 2, 0, 0, $b_width, $b_height);
    break;
  }


// 結果ファイルに出力 //
$filepath = pathinfo($fnm_new);
$ext = mb_strtolower($filepath['extension']);
$res = 1;
try {
  if ($ext === "jpg" || $ext === "jpeg") {
    imagejpeg($image_a, $fnm_new, 100);
  }
  else if ($ext === "png") {
    imagepng($image_a, $fnm_new, 9);
  }
  else if ($ext === "gif") {
    imagegif($$image_a, $fnm_new, 100);
  }
}
catch (Exception $ex) {
  $res = 0;
}

// 解放 //
imagedestroy($image_a);
imagedestroy($image_b);

// 連想配列に格納 //
$responce = [];
$responce["Result"] = $res;

// JSONに変換して結果出力 //
//echo json_encode($responce, JSON_PRETTY_PRINT);
echo json_encode($responce);

?>


[ 利用例 ]

Aファイル (背景)

Bファイル (パネル)

合成結果 NE パディング指定あり

合成結果 SE

合成結果 SW

合成結果 NW

合成結果 S