pdf2img python編

คือว่า โปรแกรมpdf24เมื่อกี้มันพัง… พอinput pdfหลายๆไฟล์พร้อมกัน มันบอกว่าหา imageที่extractแล้วเก็บไว้ใน tmp folder ไม่เจอ .. ซึ่งปิดโปรแกรมเปิดใหม่ก็ไม่หาย เหมือนจะต้องรีเซ็ตคอม…
ก็เลย ถาม chatpgtให้มันเขียนโค๊ดให้หน่อย + แก้เองเยอะอยู่
ได้ความว่า

import fitz  # pip install PyMuPDF
import os
import shutil
from pathlib import Path

def extract_images_from_pdf(pdf_path, save_folder):
    doc = fitz.open(pdf_path)
    print(pdf_path)
    save_prefix = "_".join(element[:10] for element in pdf_path.split("\\"))
    #save_prefix = pdf_path.replace("\\", "-")[0:20]
    print(save_prefix)

    img_index =0
    for page_number in range(doc.page_count):
        page = doc[page_number]
        images = page.get_images(full=True)
        #print("found images "+len(images))


        for img_info in images:
            img_index += 1
            image_index = img_info[0]
            #print(img_index,image_index)
            base_image = doc.extract_image(image_index)

            image_bytes = base_image["image"]
            image_filename = f"{save_folder}/{save_prefix}_{img_index}.jpg"

            with open(image_filename, "wb") as image_file:
                image_file.write(image_bytes)
    print("extracted images = "+str(img_index)+"\n")
    doc.close()
    
    
def extract_images_from_pdfs(pdf_folder, save_folder):
    files = [f for f in os.listdir(pdf_folder) if os.path.isfile(os.path.join(pdf_folder, f))]
    for file in files:
        #print(file)
        if file.lower().endswith(('.pdf')):
            filepath = os.path.join(pdf_folder, file)
            extract_images_from_pdf(filepath, save_folder)
    print("Done!")
            
extract_images_from_pdfs('Session 5 - Interfaces for the Body and Beyond','extracted_images')

คือใส่ชื่อ folder เป็น input แล้วอ่าน pdf ในโฟล์เดอร์นั้น extract image
ซึงอันนี้ ถ้ารูปต้นฉบับเป็น transparent มา มันจะใส่ background สีดำให้ ต่างกับตัวโปรแกรมpdf24 ที่เซฟเป็นสีขาวให้ ดูคลีนตากว่า

ละก็contrastสีเพี้ยนน ไม่รู้ว่ารูปต้นฉบับเป็นไฟล์อะไร

folder ismar นี่ล่มมาก ทั้งสีเพี้ยน ภาพมาเป็นเศษๆ ไม่รู้เป็นไร

กับอีกอย่างที่ยังทำไม่ได้คือ ถ้ารูปต้นฉบับ embed เป็น pdf มา (มักจะเป็นพวกกราฟที่อยากได้ …) ทั้งโปรแกรมpdf24 ทั้ง python lib ตัวนี้ยัง extract ออกมาให้ไม่ได้

pdf2img

พอดีจะหาไอเดียทำกราฟใส่เปเปอร์ ปกติก็จะนั่งเปิดอ่านทีละอัน นั่งcropอันที่ชอบละsaveเก็บไว้ในfolderบ้าง แปะใน powerpoint/excel บ้างแล้วแต่อารมณ์ เสร็จละก็มักจะหาไม่เจอว่ารูปนี้มาจากเปเปอร์ไหน….

ด้วยความขี้เกียจcropรูปละ เลยเซิร์จหาโปรแกรมละก็เจอ มีให้ดาวโหลดโปรแกรมลงคอมด้วยนะ
https://tools.pdf24.org/en/extract-images

คือลากไฟล์เยอะๆใส่ได้เลย ละมันจะextractรูปภาพออมาให้ ตอนที่เซฟยังแยกโฟลเดอร์ตามชื่อ paper อยู่ โชคดีที่ชื่อรูปยังมี prefix เป็นชื่อโฟลเดอร์อยู่ (ถ้าทำในเว็ป ชื่อรูปไม่มี prefix เป็น 0.png 1.png 2.png ไป)
เดี่ยวเขียน python ให้มันเอารูปออกมาจากโฟลเดอร์จะได้ดูง่ายๆ ถาม chatgpt กับเขียนเพิ่มเองอีกนิด

import os
import shutil
from pathlib import Path

def move_images_and_delete_folders(folder_path):
    print("process on :"+folder_path)
    # Get a list of all subdirectories
    subdirectories = [f for f in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))]

    # Iterate through each subdirectory
    for subdir in subdirectories:
        print(subdir)
        subdir_path = os.path.join(folder_path, subdir)
        if not os.path.isdir(subdir_path):
            print("not a directory, skip!")
            continue

        # Get a list of all files in the subdirectory
        files = [f for f in os.listdir(subdir_path) if os.path.isfile(os.path.join(subdir_path, f))]
        folder_contain_image = False
        # Iterate through each file in the subdirectory
        for file in files:
            # Check if the file is an image (you can customize this check based on your file extensions)
            if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
                # Move the image file to the parent directory
                source_file = os.path.join(subdir_path, file)
                destination_file = os.path.join(folder_path, file)
                shutil.move(source_file, destination_file)
                folder_contain_image=True

        # Delete the empty subdirectory
        if(folder_contain_image):
            os.rmdir(subdir_path)

# Replace 'your_folder_path' with the path to the folder containing subfolders
folder_path = os.getcwd()

move_images_and_delete_folders(folder_path)

説明変数

説明変数คืออะไร เหมือนจะแปลออกแต่ก็งงๆ แล้วก็มันมีชื่อแถวๆนี้อยู่หลายตัว ตัวไหนเป็นตัวไหนไม่รู้ละ เลยมาเปิดเว็ปเช็คดู

ก็จะมี กลุ่มตัวแปร X ที่เป็น input

  • 説明変数:explanatory variable ตัวแปรอธิบาย
  • 予測変数:predictor variable ตัวแปรทำนาย
  • 独立変数:independent variable ตัวแปรอิสระ

แต่แอบงง 予測変数 ตัวแปรทำนาย แปลมาแล้วชื่อเหมือนจะเป็น output

予測変数とは、結果変数 (目的変数や応答変数とも呼ばれます) を予測するために使用する入力変数です。
ตัวแปรทำนายคือ ตัวแปรinputที่ใช้ทำนายผลลัพธ์…โอเคตามนั้น
มันใช้ในการทำนาย ไม่ใช่ผลลัพธ์จากการทำนาย

ส่วนอีกกลุ่มคือ ตัวแปร Y ที่เป็น output/result มีดังนี้

  • 目的変数:response variable ตัวแปรวัตถุประสงค์
  • 結果変数:outcome variable ตัวแปรผลลัพธ์
  • 従属変数:dependent variable ตัวแปรตาม
  • 応答変数:response variable ตัวแปรตอนสนอง

เรามักจะเจอ Y กับ X เป็นคู่ๆตามนี้ (ทำไมเค้าเอา Y นำ X นะ…)

「目的変数&説明変数」
「従属変数&独立変数」

reference:
https://yoshida931.hatenablog.com/entry/2018/05/13/232801
https://best-biostatistics.com/correlation_regression/variables.html

Pdf merge and compress

pdftk : https://www.pdflabs.com/tools/pdftk-server/

gswin64 : https://ghostscript.com/releases/gsdnld.html

filenames = os.listdir()
result = ” “.join(filenames)
result

pdftk 1.pdf 2.pdf 3.pdf cat output merged.pdf

gswin64 -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 –dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile=merged_compress.pdf merged.pdf

  • -dPDFSETTINGS=/screen lower quality, smaller size. (72 dpi)
  • -dPDFSETTINGS=/ebook for better quality, but slightly larger pdfs. (150 dpi)
  • -dPDFSETTINGS=/prepress output similar to Acrobat Distiller “Prepress Optimized” setting (300 dpi)
  • -dPDFSETTINGS=/printer selects output similar to the Acrobat Distiller “Print Optimized” setting (300 dpi)
  • -dPDFSETTINGS=/default selects output intended to be useful across a wide variety of uses, possibly at the expense of a larger output file

Reference:  https://ghostscript.readthedocs.io/en/latest/VectorDevices.html#controls-and-features-specific-to-postscript-and-pdf-input

pdf to png command

gswin64 -sDEVICE=pngalpha -sOutputFile=math.png -r144 math.pdf

W: Failed to fetch

เวลาที่  sudo apt-get install อะไรสักอย่างแล้วมันขึ้น
E: Unable to locate package xxx

ในเน็ตเค้าก็จะแนะนำให้ sudo apt-get update ก่อน
แต่มันก็ขึ้น W: Failed to fetch อีก

วิธีแก้ไขคือ ให้เราเคลียร์ข้างในโฟลเดอร์ /var/lib/apt/lists ซึ่งเก็บข้อมูลแพคเกจต่างๆไว้
โดยการ rename หรือ move มันไปไว้ที่อื่น sudo mv /var/lib/apt/lists ~/
**ไม่ควรลบทิ้ง เดี่ยวอะไรหายไปแล้วจะกู้คืนไม่ได้ วุ่นวายหนักกว่าเดิม

ลอง sudo apt-get update อีกรอบ น่าจะไม่มี warning/error ใดๆ
แต่ถ้ามันไม่ได้ ก็ลอง copy ไฟล์ /etc/apt/sources.list จากเครื่องที่ install package ได้มาใส่อีกเครื่องดู (จริงๆแค่เขียน repository เพิ่มเข้าไปข้างในไฟล์ก็ได้ แต่ก็ไม่รู้ว่าต้องเขียนอะไร)

#deb cdrom:[Ubuntu 20.04.3 LTS _Focal Fossa_ - Release amd64 (20210819)]/ focal main restricted

# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://jp.archive.ubuntu.com/ubuntu/ focal main restricted
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://jp.archive.ubuntu.com/ubuntu/ focal-updates main restricted
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://jp.archive.ubuntu.com/ubuntu/ focal universe
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal universe
deb http://jp.archive.ubuntu.com/ubuntu/ focal-updates universe
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu 
## team, and may not be under a free licence. Please satisfy yourself as to 
## your rights to use the software. Also, please note that software in 
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://jp.archive.ubuntu.com/ubuntu/ focal multiverse
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal multiverse
deb http://jp.archive.ubuntu.com/ubuntu/ focal-updates multiverse
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://jp.archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse
# deb-src http://jp.archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu focal partner
# deb-src http://archive.canonical.com/ubuntu focal partner

deb http://security.ubuntu.com/ubuntu focal-security main restricted
# deb-src http://security.ubuntu.com/ubuntu focal-security main restricted
deb http://security.ubuntu.com/ubuntu focal-security universe
# deb-src http://security.ubuntu.com/ubuntu focal-security universe
deb http://security.ubuntu.com/ubuntu focal-security multiverse
# deb-src http://security.ubuntu.com/ubuntu focal-security multiverse

# This system was installed using small removable media
# (e.g. netinst, live or single CD). The matching "deb cdrom"
# entries were disabled at the end of the installation process.
# For information about how to configure apt package sources,
# see the sources.list(5) manual.

เขียน shutdown service ใน ubuntu

ใน ubuntu จะมีโปรแกรมชื่อ systemd  เป็น service manager

ไฟล์ abc.service ต่างๆ จะอยู่ใน  /etc/systemd/system เพื่อให้ service นั้นๆ run ตอนที่คอมเปิดเครื่อง/รีสตาร์ท

ไฟล์ .service ที่เราเขียนเอง จะถูกเก็บไว้เป็น symbolic link ของpathจริง ใน /etc/systemd/system

[Unit]
Description=remote shutdown service

[Service]
ExecStart=/bin/bash -c "python -m uvicorn shutdown_api:app --host 0.0.0.0 --port 7999 --reload"
Restart=always
Type=simple
WorkingDirectory=/mnt/shutdown_api/
RestartSec=10
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

จริงๆแล้ว ใช้ ExecStart=/bin/bash -c “python3.8 /mnt/shutdown_api/shutdown_api.py” ก็น่าจะได้ แต่เซิฟเวอร์ที่ใช้อยู่เป็นอะไรไม่รู้รันคำสั่งธรรมดาไม่ได้ เลยต้องพิมพ์แบบยาวๆ

import uvicorn
from fastapi import FastAPI
import subprocess

app = FastAPI()

@app.get("/")
def shutdown():
    #subprocess.run([f"shutdown -h now"], shell=True)
    password = "serverpassword"
    command = f"echo {password} | sudo -S shutdown -h now"
    print(command)
    subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)    

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7999, reload=True)

ไฟล์ python นี้คือ ให้ uvicorn server รัน FastAPI application (app)

ส่วน app = FastAPI() ก็จะเรียก def shutdown() ถ้ามี HTTP GET command ถูกเรียกใข้งาน

จากการที่เรา พิมพ์ curl http://192.168.11.122:7999   ใน terminal

ปล.  host=”0.0.0.0″ means that the server will listen on all available network interfaces on the host machine.  This makes the server accessible from any IP address on the network.

วิธีติดตั้ง service

1. sudo systemctl daemon-reload
#to reload the systemd manager configuration

2. sudo systemctl enable shutdown.service
#to enable the service to start at boot (create symbolic link if not exist)

3. sudo systemctl start shutdown.service
#to start the service

4. sudo systemctl status shutdown.service
#to check the status of the service

ถ้า  host=0.0.0.0 ตามที่เขียนไว้ใน python file คือ ok

แต่ถ้าเป็น host=127.0.0.1 คือเป็น loopback จะไม่สามารถเรียก http get จาก คอมเครื่องอื่นในเน็ตเวิคได้

5. netstat -an|more #to check all available services

ปล. เขียนแยกหลายๆ decorator ก็เหมือนจะได้นะ

@app.get(“/shutdown”)
async def shutdown():

@app.get(“/restart”)
async def restart():

ส่วน HTTP POST ดูใช้งานยากอยู่ ยังไม่เคยลอง แต่ประมาณนี้
@app.post(“/items/”)
async def create_item(item: Item):

curl --header "Content-Type: application/json" \
     --request POST \
     --data '{"name": "example item", "price": 9.99}' \
     http://localhost:8000/items/

ตรง –data คือ ส่ง json structure เข้าไปเป็น input ที่ฟังก์ชัน

Create Avatar for Unity

From: https://support.readyplayer.me/hc/en-us/articles/360020740897-How-do-I-use-a-GLB-model-in-Unity-

  1. Create and download your avatar from https://readyplayer.me/
  2. Import your file into Blender – File/Import/gITF 2.0 (.glb/gltf)
  3. Edit your model (remove extra bones in the head, fingers, etc.)
  4. Go to the Texture Paint tab and select “View” in the top left of the Image Editor panel
  5. Select each texture from the drop-down at the top
  6. At the top left, click Image/Save As… (or Shift + Alt + S) and select your destination
  7. Export your model as an FBX – File/Export/FBX (.fbx)
  8. Import your model and textures into Unity
  9. Click the FBX avatar in the Assets window
  10. In the Inspector window, change the Location to “Use External Materials (Legacy)” and apply
  11. If some base textures don’t appear, click on the body part and manually assign the texture to the correct map (Albedo).

Unity Shader for Generating Annotation Image

Game scene:

  • Attach the 2nd (normal view) and 3rd (segmentation view) cameras to the game scene
  • Create Renderer Target x2 to receive images from the cameras
  • Create UI/Raw Image to show the images from the cameras

The segmentation view camera: attach the below script

using UnityEngine;
[ExecuteInEditMode]
public class ReplacementShaderTest : MonoBehaviour
{
    private Camera _camera;
    private Shader _shader;
    void OnEnable()
    {
        _camera = GetComponent<Camera>();
        _shader = Shader.Find("ReplaceObjectColorInCameraView");
        _camera?.SetReplacementShader(_shader, "Annotation");

    }
    private void OnDisable()
    {
        _camera?.ResetReplacementShader();
    }
}

We will have the below shader code in Assets folder. It is called by ReplaceObjectColorInCameraView.cs. It will check the Annotation tag set in another script and change the gameobject material color.

Shader "ReplaceObjectColorInCameraView"
{
	SubShader
	{
		Tags { "Annotation" = "green" }
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			float4 vert(float4 vertex : POSITION) : SV_POSITION
			{
				return UnityObjectToClipPos(vertex);
			}
			fixed4 frag() : SV_Target
			{
				return fixed4(0, 1, 0, 1); //green
			}
			ENDCG
		}
	}
	SubShader
	{
		Tags { "Annotation" = "red" }
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			float4 vert(float4 vertex : POSITION) : SV_POSITION
			{
				return UnityObjectToClipPos(vertex);
			}
			fixed4 frag() : SV_Target
			{
				return fixed4(1, 0, 0, 1); //red
			}
			ENDCG
		}
	}
}

At any gameobject, attach the below code to set an annotation tag.
A gameobject may contain many materials or has a material attached in its child object.

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

[ExecuteInEditMode]
public class SetShaderTagsAnnotation : MonoBehaviour
{
    public enum AnnotationType
    {
        green, red
    }
    public AnnotationType annotation_name; 

    void Start()
    {
         List<Material> list_material = obj.GetComponent<Renderer>().materials.ToList();
         foreach (Material mat in list_material)
         {
             mat.SetOverrideTag("Annotation", annotation_name.ToString());
         }
         ApplyAnnotation(gameObject.transform);
    }
    void ApplyAnnotation(Transform obj)
    {
        Renderer myRenderer = obj.GetComponent<Renderer>();
        if (myRenderer != null)
        {
            myRenderer.material.SetOverrideTag("Annotation", annotation_name.ToString());
            //Debug.Log(obj.name + " is set to " + annotation_name.ToString());
        }
        else
        {
            //Debug.Log(obj.name + " has no Renderer component");
            TraverseHierarchy(obj.transform);
        }
    }

    void TraverseHierarchy(Transform parent)
    {
        //Debug.Log("TraverseHierarchy of " + parent.name);
        foreach (Transform child in parent)
        {
            ApplyAnnotation(child);
        }
    }

ShowPath

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PathReader : MonoBehaviour
{
    public GameObject MarkStart, MarkGoal, MarkFP;
    public float smooth_distance;
    public TextAsset filename;
    //private List<string> file_data_line;
    private List<Vector3> positions, rotations;

    private LineRenderer lineRenderer;

    void Awake()
    {
        lineRenderer = GetComponent<LineRenderer>();
        //file_data = System.IO.File.ReadAllLines(filename_path);
        //Debug.Log(filename);
    }

    void Start()
    {
        List<string> file_data_each_line = TextAssetToListString(filename);
        ListStringToListVector(file_data_each_line, out positions, out rotations, smooth_distance);
        //MapToGroundPosition(); //cannot change the value of List<Vector3> after assigned.

        //Assign positinos to line renderer
        lineRenderer.positionCount = positions.Count;
        lineRenderer.SetPositions(positions.ToArray());

        //Assign Mark object position
        MarkStart.transform.position = positions[0];
        MarkGoal.transform.position = positions[positions.Count-1];
        MarkFP.transform.position = positions[1];

        Debug.Log("Positions count = " + positions.Count);
    }

    private List<string> TextAssetToListString(TextAsset ta)
    {
        return new List<string>(ta.text.Split('\n'));
    }


    private void ListStringToListVector(List<string> list_text, out List<Vector3> list_pos, out List<Vector3> list_rot, float smd)
    {
        list_pos = new List<Vector3>();
        list_rot = new List<Vector3>();

        // 1st line is label
        // 2nd line add to thevector
        string[] columns = list_text[1].Split(',');
        Vector3 load_position = new Vector3(float.Parse(columns[1]), 0f, float.Parse(columns[3])); //set y to ground
        Vector3 load_rotation = new Vector3(float.Parse(columns[4]), float.Parse(columns[5]), float.Parse(columns[6]));
        positions.Add(load_position);
        rotations.Add(load_rotation);

        for (int i = 2; i < list_text.Count; i++) // from 3nd line, check distance before add to the vector
        {
            //Debug.Log(line);
            columns = list_text[i].Split(',');

            if (columns.Length != 7) // not enough information to extract (end of line)
                return;

            //Debug.Log(i+" "+columns.Length);

            //Vector3 load_position = new Vector3(float.Parse(columns[1]), float.Parse(columns[2]), float.Parse(columns[3]));
            load_position = new Vector3(float.Parse(columns[1]), 0f, float.Parse(columns[3])); //set y to ground
            load_rotation = new Vector3(float.Parse(columns[4]), float.Parse(columns[5]), float.Parse(columns[6]));

            if(Vector3.Distance(positions[positions.Count-1], load_position) > smd)
            {
                positions.Add(load_position);
                rotations.Add(load_rotation);
            }

        }
    }



}