2023年11月5日日曜日

PythonからのOpenCVを使ってpdfを比較する(1)

python-opencvを使ってpdfを画像として比較する。

まぁだいたい、ここに書いてあるコードが拡散しているらしい。が、記述が多いので、条件をシンプルにしてコードをシンプルにする。で、ずばり1ページ目しか読み込まない。って大胆にシンプル化。

まずは、比較用の素材を準備。まぁ自分のブログを印刷したものです。
リファレンス : Sunday Engineer_1_ref.pdf
比較対象 : Sunday Engineer_1_cmp.pdf
で、python-opencvのインストールやら設定やらは参考サイトを参照されたい。

TypeError: 'numpy._DTypeMeta' object is not subscriptable
ってエラーが出るときは
sudo apt remove python3-numpy
からの
pip install numpy

では、相変わらずのいきなりな感じで、
pdf_compare.py
  1. import cv2
  2. from pdf2image import convert_from_path
  3.  
  4. import numpy as np
  5. #import sys
  6.  
  7. ref_imgs_in=convert_from_path('Sunday Engineer_1_ref.pdf')
  8. ref_cv_img=np.asarray(ref_imgs_in[0])#1ページ目
  9. ref_cv_img=cv2.cvtColor(ref_cv_img,cv2.COLOR_RGB2BGR)
  10.  
  11. cmp_imgs_in=convert_from_path('Sunday Engineer_1_cmp.pdf')
  12. cmp_cv_img=np.asarray(cmp_imgs_in[0])#1ページ目
  13. cmp_cv_img=cv2.cvtColor(cmp_cv_img,cv2.COLOR_RGB2BGR)
  14.  
  15. tmp_cv_img=np.full(ref_cv_img.shape,0,dtype=np.uint8)
  16.  
  17. #pos_diff=np.where(ref_cv_img!=cmp_cv_img)
  18. tmp_cv_img=np.where((ref_cv_img!=cmp_cv_img),(255,255,255),tmp_cv_img)
  19.  
  20. cv2.imwrite('diff.png',tmp_cv_img)

まじで恐ろしく簡単なコードです。OpenCVが画像をndarrayで持っていることから、np.whereで相違点を抽出できます。

で、結果はこちら。
diff.png
これでもうオンラインでの間違い探しクイズは成立しない^^

さて、今回は同じソースからpdfを作成して微妙に変えた部分を抽出しましたが、pdfにjpeg形式で画像が埋まっているとpdf生成時の設定によっては画像部分に塩粒みたいな相違点が検出されてしまいます。こういうのをノイズとして相違点としないようにするにはどうするか。ってのをやりたい。が、やるかもしれないし、やらないかもしれない。

2023年11月3日金曜日

ゼロからのCMake(2)

 

今まで避けてきた「CMake」に挑戦。動的ライブラリ(Windowsで云うDLL)とそれを呼び出す実行ファイルを作ってみる。

動的ライブラリはリンク時に指定するんじゃなく、dlopenを使う。なんかもう、こっちしかわからんくなってきた。

./study3.cpp

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <dlfcn.h>
  4. //#include "keeloq/include/keeloq.hpp"
  5.  
  6. void *hdll;
  7. typedef uint32_t (*keeloq_enc_t)(uint32_t pr,uint64_t kr);
  8. typedef uint32_t (*keeloq_dec_t)(uint32_t cr,uint64_t kr);
  9.  
  10. keeloq_enc_t keeloq_enc;
  11. keeloq_dec_t keeloq_dec;
  12.  
  13. int main(int argc,char** argv){
  14. uint32_t pr=0xf741e2db;
  15. uint64_t kr=0x5cec6701b79fd949;
  16. uint32_t cr;
  17.  
  18. hdll = dlopen("./keeloq/libkeeloq.so", RTLD_LAZY);
  19. if(hdll==NULL){return 1;}
  20. keeloq_enc=(keeloq_enc_t)dlsym(hdll,"keeloq_enc");
  21. keeloq_dec=(keeloq_dec_t)dlsym(hdll,"keeloq_dec");
  22.  
  23. cr=keeloq_enc(pr,kr);
  24. printf("%08X\n",cr);
  25. pr=keeloq_dec(cr,kr);
  26. printf("%08X\n",pr);
  27. dlclose(hdll);
  28. return 0;
  29. }
./CMakeLists.txt
  1. cmake_minimum_required(VERSION 3.1)
  2. project(study3 CXX)
  3. add_subdirectory(./keeloq)
  4. add_executable(study3 study3.cpp)
  5. #target_link_libraries(study3 keeloq)
./keeloq/CMakeLists.txt
  1. cmake_minimum_required(VERSION 3.1)
  2. project(keeloq_lib
  3. VERSION 1.0.0
  4. DESCRIPTION "Keeloq library"
  5. LANGUAGES CXX)
  6. add_library(keeloq SHARED ./src/keeloq.cpp)
  7. #target_compile_features(keeloq PRIVATE cxx_std_11)
  8. #target_include_directories(keeloq SHARED ./include)
  9. set_target_properties(keeloq
  10. PROPERTIES
  11. VERSION ${PROJECT_VERSION})
./keeloq/include/keeloq.hpp
  1. #ifndef _KEELOQ_H_
  2. #define _KEELOQ_H_
  3. #include <stdint.h>
  4. extern "C" uint32_t keeloq_enc(uint32_t pr,uint64_t kr);
  5. extern "C" uint32_t keeloq_dec(uint32_t cr,uint64_t kr);
  6. #endif
./keeloq/src/keeloq.cpp
  1. #include <stdint.h>
  2. extern "C" uint32_t keeloq_enc(uint32_t pr,uint64_t kr){
  3. uint32_t nlf_table=0x3a5c742e;
  4. uint32_t nlf_arg;
  5. uint32_t nlf;
  6. uint32_t newz;
  7. uint32_t i;
  8. for(i=0;i<528;i++){
  9. nlf_arg=((pr&0x80000000)>>(31-4))
  10. |((pr&0x04000000)>>(26-3))
  11. |((pr&0x00100000)>>(20-2))
  12. |((pr&0x00000200)>>(9-1))
  13. |((pr&0x00000002)>>(1-0));
  14. nlf=((nlf_table>>nlf_arg)&0x00000001);
  15. newz=nlf^((pr&0x00010000)>>16)^(pr&0x00000001)^(uint32_t)(kr&0x0000000000000001);
  16. pr=(newz<<31)|(pr>>1);
  17. kr=((kr&0x0000000000000001)<<63)|(kr>>1);
  18. }
  19. return pr;
  20. }
  21. extern "C" uint32_t keeloq_dec(uint32_t cr,uint64_t kr){
  22. uint32_t nlf_table=0x3a5c742e;
  23. uint32_t nlf_arg;
  24. uint32_t nlf;
  25. uint32_t newz;
  26. uint32_t i;
  27. for(i=0;i<528;i++){
  28. nlf_arg=((cr&0x40000000)>>(30-4))
  29. |((cr&0x02000000)>>(25-3))
  30. |((cr&0x00080000)>>(19-2))
  31. |((cr&0x00000100)>>(8-1))
  32. |((cr&0x00000001)>>(0-0));
  33. nlf=((nlf_table>>nlf_arg)&0x00000001);
  34. newz=nlf^((cr&0x00008000)>>15)^((cr&0x80000000)>>31)^(uint32_t)((kr&0x0000000000008000)>>15);
  35. cr=(cr<<1)|(newz);
  36. kr=((kr&0x8000000000000000)>>63)|(kr<<1);
  37. }
  38. return cr;
  39. }
いつものいきなりな感じで。
・マングリングをさせないために関数にextern "C"をつけた。Windowsでは__stdcallってのもつけるけど、Linuxではいらんらしい。
・CMakeLists.txtでtarget_link_libraries(study3 keeloq)をコメント化。いらんはずなので。
・keeloq/CMakeLists.txtの"target_include_directories(keeloq SHARED ./include)"はあるとエラーが出るのでコメント化。意味はわかってないが。
、、、でけた。イイネCMake。
ビルド中にLinking sahred library libkeeloq.soって出ているのがあれ?って思うけど、今日は掘らない。

あ、お伝えしていなかったのですが、ちょっと古いPCを入手して、それでLinuxマシンをこさえたのでこの手の挑戦はLinuxでやてます。WSLでも同じようにできると思いますが、やっぱりLinuxマシンのほうが楽しいじゃん。なんとなく。