• Komputer,  Programming,  Software

    OCR

    Beberapa waktu lalu sempet ngasih komentar di twitter atas postingan orang yang isinya protes atas data dari website Kementrian Kesehatan tentang vaksinasi Covid-19. Protes karena data yang disajikan berupa image (gambar) dan menurut orang yg posting data yang disajikan tidak “properly consumable by the public?”

    Saya pikir kalau orang gak suka data ditampilkan dalam bentuk image, berarti orang itu mau “mengambil” data itu lalu (mungkin) diolah dan disajikan dalam bentuk lain. Otomatis saya kasih tanggapan “Coba ambil gambarnya, split utk di-OCR utk dapet teksnya”. Jawaban khas “data scraper” 🙂

    Eh ternyata orangnya gak suka jawaban saya, dia bales lagi “The point is that the public *don’t* have to do the things you mentioned”. Saya setuju, masyarakat umum (“the public”) gak mungkin harus nge-OCR data dalam bentuk image. “The public” cukup lihat saja langsung image-nya, dan harusnya gak peduli tentang bagaimana data ditampilkan, yang penting kelihatan pake mata. Intinya bagi saya, orang yang peduli dengan bagaimana data ditampilkan bukan bagian dari “the public”.

    Terlepas dari perdebatan di atas, jiwa programmer saya terus tergelitik untuk nyoba bikin program yang melakukan OCR ke data vaksinasi covid-19 yang disebut di atas. Langkah pertama yg saya lakukan adalah: cari pake google dengan kata kunci “javascript ocr“.

    Yang muncul paling atas tentu saja “Tesseract.js“, proyek tesseract memang ngerajain bidang OCR. Tapi saya mau nyari OCR yg “slim”, yang cukup dengan 1 file js dan sangat mudah digunakan. Dan ternyata apa yg saya mau muncul di halaman pertama juga, namanya Ocrad.js.

    Ocrad.js sebenernya bukan benar2 implementasi teknik OCR pake javascript, karena menurut yang buat, Ocrad.js itu hasil konversi program Ocrad yang dibuat pake C++ ke WebAssembly pake Emscripten. Jadi jangan harap bisa “ngintip” cara OCR pake Javascript murni di Ocrad.js.

    Oke, langsung aja, ini langkah2 bikin program OCR untuk nge-scrap data image dari Kemenkes tentang vaksinasi covid-19.

    1. Install Node.js
    2. Clone Ocrad.js dari github. Sebenernya yang dibutuhkan cuma 1 file, yaitu file ocrad.js, tapi ada baiknya kalo di-clone semua aja karena ada contoh2nya yang bisa dipelajari.
    3. Buat 1 folder untuk programnya, lalu buat dua file (yang saya sertakan di bawah) di dalam folder tsb. Sebenernya yang paling penting cuma file vaksinasi.js, file package.json cuma untuk mempermudah instalasi node-module yang dibutuhkan.
    4. Buka command prompt, ganti folder aktif ke folder program di atas, terus ketik perintah:
      • Kalau ada file package.json, cukup pake 1 perintah: npm install
      • Kalau tidak ada file package.json ada dua perintah:
        • npm i --save canvas
        • npm i --save request
    5. Sesudah itu tinggal jalankan script-nya: node vaksinasi.js

    File: package.json

    {
      "name": "vaksinasi-covid19",
      "version": "1.0.0",
      "description": "OCR image data vaksinasi covid-19 dari Kemenkes RI ",
      "main": "vaksinasi.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "Ureh",
      "license": "ISC",
      "dependencies": {
        "canvas": "^2.7.0",
        "request": "^2.88.2"
      }
    }

    File: vaksinasi.js

    var OCRAD = require('./ocrad.js');
    var Canvas = require('canvas');
    var fs = require('fs');
    var request = require('request');
    
    var Image = Canvas.Image;
    var png = "https://www.kemkes.go.id/web/assets/images/infografis/vaksin/VAKSINASI-Infografis.png";
    png = "http://localhost/infografis.png"; // for local testing
    
    function downloadFile(url, dest, cb) {
      console.log('Downloading %s', url);
      var file = fs.createWriteStream(dest);
    
      var req = request.get(url);
      req.pipe(file).on('error', function(err) { // Handle errors
        fs.unlink(dest); // Delete the file async. (But we don't check the result)
        if (cb) cb(err.message);
      });
    
      file.on('finish', function() {
        file.close(cb);  // close() is async, call cb after close completes.
      });
    }
    
    console.log('Starting OCR');
    
    downloadFile(png, 'infografis.png', function(){
    	fs.readFile(__dirname + '/infografis.png', function(err, src) {
    	  if (err) {
    		throw err;
    	  }
    
    	  var dw = 383;
    	  var dh = 439;
    	  var xl = 4;
    	  var xl2 = 4;
    
          var img = new Image();
    	  img.src = src;
    
    // JUDUL ATAS
    	  console.log('\n');
    	  var c0 = new Canvas.createCanvas(1280*xl, 195*xl);
    	  var x0 = c0.getContext('2d');
    	  x0.drawImage(img, 0,0,1280,195, 0,0,1280*xl,195*xl);
    	  console.log(OCRAD(c0));
    
    // PANEL KIRI
    	  console.log('\n');
    	  var c1 = new Canvas.createCanvas(dw*xl, dh*xl);
    	  var x1 = c1.getContext('2d');
    	  x1.drawImage(img, 35,207,dw,dh, 0,0,dw*xl,dh*xl);
    	  console.log(OCRAD(c1));
    
    // PANEL TENGAH
    	  console.log('\n');
    	  var c2 = new Canvas.createCanvas(dw*xl2, dh*xl2);
    	  var x2 = c2.getContext('2d');
    	  //x2.filter = 'grayscale(1) invert(1)';
    	  x2.drawImage(img, 447,207,dw,dh, 0,0,dw*xl2,dh*xl2);
    
    	  // konversi ke hitam-putih dan di invert
    	  // karena text putih gak kebaca
    	  // filter di canvas context gak jalan
    	  const imgData = x2.getImageData(0, 0, dw*xl2, dh*xl2);
    	  for (i = 0; i < imgData.data.length; i += 4) {
    	  	let count = imgData.data[i] + imgData.data[i + 1] + imgData.data[i + 2];
    		let colour = 255;
    		if (count > 500) colour = 0;
    
    		imgData.data[i] = colour;		// red
    		imgData.data[i + 1] = colour;	// green
    		imgData.data[i + 2] = colour;	// blue
    		imgData.data[i + 3] = 255;		// alpha
    	  }
    	  x2.putImageData(imgData, 0,0);
    	  console.log(OCRAD(c2));
    
    // PANEL KANAN
    	  console.log('\n');
    	  var c3 = new Canvas.createCanvas(dw*xl, dh*xl);
    	  var x3 = c3.getContext('2d');
    	  x3.drawImage(img, 859,207,dw,dh, 0,0,dw*xl,dh*xl);
    
    	  // konversi ke hitam-putih tdk mempengaruhi output OCR
    	  /*
    	  const imgData3 = x3.getImageData(0, 0, dw*xl, dh*xl);
    	  for (i = 0; i < imgData3.data.length; i += 4) {
    	  	let count = imgData3.data[i] + imgData3.data[i + 1] + imgData3.data[i + 2];
    		let colour = 0;
    		if (count > 300) colour = 255;
    
    		imgData3.data[i] = colour;
    		imgData3.data[i + 1] = colour;
    		imgData3.data[i + 2] = colour;
    		imgData3.data[i + 3] = 255;
    	  }
    	  x3.putImageData(imgData3, 0,0);
    	  */
    	  console.log(OCRAD(c3));
    
    	});
    });

    Sekarang kita bahas programnya, program ini adalah hasil modifikasi dari contoh Ocrad.js.

    Baris 1 s.d. 8 adalah inisialisasi variabel, dimana di baris ke-8 saya set ulang variabel png supaya program mengambil gambar dari localhost, karena saya akan mencoba mengulang-ulang program dengan image yang sama biar gak membebani servernya kemenkes.

    Baris 10 s.d. 23 adalah fungsi untuk mengunduh file lalu menjalankan callback saat proses pengunduhan selesai. Fungsinya dapet dari codota.com.

    Bahasannya segitu dulu aja yah. Lain kali disambung lagi.

  • Text File
    Komputer,  Software

    All in one

    Entri blog saya sebelumnya yg judulnya “Demam Text“, saya nemuin TiddlyWiki. Program yg keren banget walaupun ada beberapa kekurangan (menurut saya). Yang saya pasang itu versi nodejs, bisa dibilang harus ada server biarpun sederhana.

    Karena ternyata pake TiddlyWiki tidak sesederhana yang saya mau, akhirnya saya bikin deh yg 1 file teks isinya semua catetan saya. Nah, yg ini ada beberapa hal yang agak maksa, saya tambah beberapa catatan “meta” yg menurut saya berguna.

    Yang pertama adalah tiap bagian pasti saya kasih “Judul”. Tiap judul punya 1 entri, untuk yang entri-nya mirip2 saya kelompokin lagi jadi punya “Judul” dan “Sub Judul”. Selain itu saya punya entri “Index” di posisi teratas yang sebenernya “daftar isi” dari semua judul dan sub-judul yg ada.

    Oh iya, untuk data2 sensitif (password dkk) dicatat dalam kondisi terenkripsi. Awalnya pake Notepad++ dengan plugin yang bisa enkrip/dekrip teks yang diblok, tapi karena gak ada fasilitas “split window” (biar gampang edit index dan isinya) akhirnya saya pake Atom.

    Sebenernya udah punya rencana untuk bikin kaya NoteJS tapi yg fleksibel, 1 html (dengan semua JavaScript di-embed) dengan data tetep pake LocalStorage, tapi data gak semuanya di-enkrip, jadi kalo ada entri2 yg sensitif aja yg di-enkrip. Dan seperti NoteJS, data bisa diunduh dalam bentuk JSON.

    Kaya’nya itu nanti deh, untuk NoteJS versi 2.

    Udah ah.

  • Hardware,  Komputer,  Software,  Teknologi

    Kembali Ke Asal

    Gak usah ribet dan ribut mengartikan judul blog ini, setiap saya tulis entri blog baru lebih dari 50% kemungkinannya tentang teknologi komputer. Termasuk entri blog ini.

    Sebelumnya, saya memakai Raspberry Pi untuk CCTV dan OrangePi untuk nyoba berbagai server. Tapi sekarang saya nyoba-nyoba OrangePi untuk sesuatu yang memang tugasnya: connect ke hardware. Hardware yang saya colokin juga bukan yang aneh-aneh, cuma layar dot-matrix dengan backlight yg dibuat untuk Nokia 5110. Layar yang cuma 1,5″ dan punya resolusi 84×48 pixel, monokrom.

    Saya coba berbagai module python, tapi gak ada yang cocok. Bahkan sampai nyoba install Armbian versi lawas karena rata-rata softwarenya juga udah berumur 2 sampai 5 tahun yang lalu.

    Sebenernya sebelum softwarenya, saya juga pusing masalah nyambungin pin-pin layar ke pin yg di OrangePi. Akhirnya, sesudah beberapa kali begadang dapet juga konfigurasi yang pas.

    LCD Nokia 5110OrangePi Lite
    RSTGPIO 24 (pin ke-18)
    CECS0 (pin ke-24)
    DCGPIO 23 (pin ke-16)
    DINMOSI (pin ke-19)
    CLKSCLK (pin ke-23)
    VCC3.3V (pin ke-1)
    BL (backlight)GPIO 22 (pin ke-15)
    GNDGround (pin ke-6)

    Bagi yang nyari-nyari referensi pin OrangePi seperti saya, bisa lihat di https://github.com/leech001/Temp_control

    Kenapa sampai lama? Karena pada saat programnya jalan dan di layar tidak ada yang tampil, saya tidak tau itu dari wiring atau dari programnya. Dan sesudah mencoba berbagai konfigurasi kabel, akhirnya saya berhasil menghidupkan layar kecil itu pake program dari https://github.com/bitbank2/nokia5110

    Satu masalah selesai, saya sudah bisa nulis ke layar, terus apa yang harus saya tulis? Sesudah mikir sebentar saya putuskan untuk menampilkan informasi sistem sederhana.

    Nah, informasi sederhana yang mau ditampilkan ini jadi masalah karena si program ditulis pake bahasa C dan kemampuan bahasa C saya minim banget, padahal kalo saya bisa nulis pake bash script enak banget, karena saya bisa nyari berbagai informasi sistem pake bash script (– di sini ada jeda sedikit sampe “lampu” ide saya nyala –).

    Ternyata solusinya sederhana, tinggal buat program yang menampilkan tulisan dari parameter saat eksekusi. Gak sampe 10 menit akhirnya programnya jadi.

    Dan ternyata, apa yang saya lakukan sudah dilakukan oleh orang lain: https://github.com/nopnop2002/Raspberry-pcd8544

    Mungkin nanti saya coba-coba itu program. Untuk sementara case closed. Eh, to be continued…

  • Komputer,  Software

    Remote Android from Computer

    To the point aja, abis nyari-nyari cara ngeremote hape android dari komputer, soalnya kaya’nya susah deh nyari di playstore, biarpun ada nanti harus lewat 3rd party server kaya Team Viewer.

    Tapi dapet juga scrcpy yang open source dan gratis. Bisa dipake tanpa setting macem2, cuma aktifkan adb debugging. Terus dobel-klik file .exe nya langsung jalan, jangan lupa colokin dulu hapenya pake kabel usb ke komputer. Di websitenya dibilang bisa juga pake WiFi, tapi saya pernah nyoba dan gak stabil, lambat banget. Gak tau juga sih, siapa tau aja itu masalahnya cuma ada di device saya aja.

    Dan sempet bingung waktu kondisi hape lagi pas layarnya mati, kan ada lock screen, nah itu di klik atau digeser ke atas gak bisa2. Ternyata harus klik kanan dulu baru bisa drag layar ke atas.

    Lihat videonya aja:

    Keren. Main game Merge Dragons! di komputer pake mouse enak juga, apalagi kalo dimainin full-screen (tekan Ctrl+F). Mantap.

    Udah ah.

  • TiddlyWiki
    Komputer,  Software,  Teknologi

    TiddlyWiki: Automation

    Di blog saya yg lain, saya pernah nulis tentang TiddlyWiki (versi Node JS) yang bisa dipasang di Android yg terinstall Termux. Waktu itu sumber data ada di notebook yg biasa saya pake, jadi kalo mau update2 saya di komputer lokal, abis itu update ke hosting di temang.ga masih manual (lihat: http://blog.sedjat1.dx.am/2019/12/tiddlywiki-goes-mobile/ ).

    Begitu ada Raspberry Pi, saya pindahin master TiddlyWiki kesana, tapi repotnya waktu mau update ke berbagai device karena masih manual jadi repot banget. Akhirnya karena ada beberapa update yg cukup penting, saya cari2 cara biar backup ke cloud-nya juga gampang.

    Nyarinya gak susah, sebentar aja ketemu cara upload data ke dropbox. Jadi sekarang kalo mau backup ke cloud tinggal jalanin 1 script, mau update yg di berbagai device juga sama, tinggal jalanin 1 script. Udah gitu sebenernya bisa juga kalo mau masukin ke cron biar bisa otomatis backup ke cloud tiap jam tertentu (blm dibikin, baru dapet ide pas nulis blog ini).

    Udah ah.