[Python]332 画像ファイルの全ピクセル色情報をCSV化

[M1 Mac, Big Sur 11.6.5, Python 3.10.0]

[Python]330に関連して画像ファイルの全ピクセル色情報を取得しCSVファイルとして出力するコードを記録しておきます。

from PIL import Image
import numpy as np
import csv

img_array = np.array(Image.open("test.png"))

# 全ピクセルの色情報を取得
list_rgba = img_array[:, :, (0, 1, 2, 3)]
# list_rgb = img_array[:, :, (0, 1, 2)] jpgの場合

with open("test.csv", 'w') as f:
    writer = csv.writer(f,lineterminator='\n')
    writer.writerows(list_rgba)

[C++] 13 Qt5 GUIアプリ作成 QtWidgets

[M1 Mac, Big Sur 11.6.5]

GUI画面が出来上がりました。基本的にはPyQt6版のコードをコピペしてメソッドのピリオドを->に書き換えただけです。オブジェクト作成の際にnewを付けたり、行の最後にセミコロンを入れるのを忘れがちでした。

次はボタン動作ですが、Qtではシグナル/スロットという仕組みになっています。ざっと説明を読んだものの今ひとつピンとこないです。

#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QRadioButton>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QWidget>
#include <QMainWindow>

int main(int argc, char *argv[]){
    QApplication app(argc, argv);

    QMainWindow* mainWin = new QMainWindow();
    mainWin->setGeometry(100,100,360,220);
    mainWin->setWindowTitle("IMAGE INSPECTOR");
    mainWin->setStyleSheet("background: '#708090';");

    QLabel* file = new QLabel(mainWin);
    file->setText("File");
    file->setGeometry(15,15,35,16);
    file->setStyleSheet("foreground: '#FFFAFA';font-size:12px;");

    QLineEdit* input= new QLineEdit(mainWin);
    input->setGeometry(50,10,220,25);
    
    QPushButton* execution = new QPushButton(mainWin);
    execution->setText("実行");
    execution->setGeometry(290,10,50,30);
    execution->setStyleSheet("foreground: '#FFFAFA';font-size:12px;");
    QPushButton::connect(execution, SIGNAL( clicked() ),&app, SLOT(quit()) );

    QPushButton* clear = new QPushButton(mainWin);
    clear->setText("クリア");
    clear->setGeometry(290,50,50,30);
    clear->setStyleSheet("foreground: '#FFFAFA';font-size:12px;");

    QButtonGroup* rbtns = new QButtonGroup(mainWin);
    QRadioButton* inspect = new QRadioButton(mainWin);
    inspect->setText("Inspect");
    inspect->setGeometry(50,40,90,20);
    inspect->setChecked(true);
    rbtns->addButton(inspect);
    
    QRadioButton* resize_img = new QRadioButton(mainWin);
    resize_img->setText("Resize");
    resize_img->setGeometry(50,65,90,20);
    rbtns->addButton(resize_img);

    QLabel* width_label = new QLabel(mainWin);
    width_label->setText("W");
    width_label->setGeometry(135,70,15,10);
    width_label->setStyleSheet("font-size:10px;");
    
    QLineEdit* width= new QLineEdit(mainWin);
    width->setGeometry(155,65,45,20);
    
    QLabel* height_label = new QLabel(mainWin);
    height_label->setText("H");
    height_label->setGeometry(205,70,15,10);
    height_label->setStyleSheet("font-size:10px;");
        
    QLineEdit* height= new QLineEdit(mainWin);
    height->setGeometry(220,65,45,20);
        
    QRadioButton* icns = new QRadioButton(mainWin);
    icns->setText("icns作成");
    icns->setGeometry(50,90,90,20);
    icns->setToolTip("PNG file[2048*2048,72px] required");
    rbtns->addButton(icns);
    
    QTextEdit* output = new QTextEdit(mainWin);
    output->setGeometry(50,115,240,100);
    
    mainWin->show();
    return app.exec();
}

[Python]331 PyQt6 icnsファイル作成コード修正

[M1 Mac, Big Sur 11.6.5, Python 3.10.0]

[Python]329のコードを修正しました。以下の通りになります。

修正前のコードでも動作しますが、jpgファイルへの変換により透過部分が黒くなる上に、不可逆圧縮することで図形周辺画素の色データにズレが生じています。pngのままでも解像度を上げられるのでその方が良いでしょう。

前回330の記事でnumpyを使った透過部分黒色化対策方法を紹介しましたが、pngのままicnsファイルを作れるようになったためnumpyは不要になりました。Qt5への移植もスムーズに進みそうです。

from PIL import Image
import subprocess, os
from PyQt6.QtWidgets import QDialog,QPushButton,QLabel
from PyQt6.QtCore import Qt

class MakeIcns():
    def make(self, filepath0, window):
        img = Image.open(filepath0)
        print(str(img.size))
        if str(img.size)=="(2048, 2048)": # 2048*2048 dpi=72
            filepath1 = ".".join(filepath0.split(".")[:-1]) + "1.png" # 1024*1024 dpi=144
            filepath2 = ".".join(filepath0.split(".")[:-1]) + "2.png" # 512*512 dpi=72
            filedir = "/".join(filepath0.split("/")[:-1]) + "/" + (filepath0.split("/")[-1]).split(".")[-2] + ".iconset/"
            
            os.mkdir(filedir)

            img = Image.open(filepath0)
            
            # 1024*1024 dpi=144
            img_resize2 = img.resize((1024,1024))
            img_resize2.save(filepath1,dpi = (144, 144))
            
            # 512*512 dpi=72
            img_resize = img.resize((512,512))
            img_resize.save(filepath2,dpi = (72, 72))

            pixels = [32, 64, 256, 512, 1024]
            pixels2 = [16, 32, 128, 256, 512]
            filepaths = ['icon_16x16@2x.png','icon_32x32@2x.png','icon_128x128@2x.png','icon_256x256@2x.png','icon_512x512@2x.png']
            filepaths2 = ['icon_16x16.png','icon_32x32.png','icon_128x128.png','icon_256x256.png','icon_512x512.png']

            # dpi=144の各種pngファイル作成
            for pixel,file in zip(pixels,filepaths):
                img = Image.open(filepath1)
                img_resize = img.resize((pixel,pixel))
                img_resize.save(filedir + file, dpi = (144, 144))
                img.close()

            # dpi=72の各種pngファイル作成    
            for pixel,file in zip(pixels2,filepaths2):
                img = Image.open(filepath2)
                img_resize = img.resize((pixel,pixel))
                img_resize.save(filedir + file, dpi = (72, 72))
                img.close()

            # icnsファイル作成
            dir = "/".join(filepath0.split("/")[:-1])
            iconset = (filepath0.split("/")[-1]).split(".")[-2] + ".iconset"
            cmd = f'iconutil -c icns {iconset}'
            subprocess.run(cmd, cwd=dir,shell=True)
            
            os.remove(filepath1)
            os.remove(filepath2)
        else:
            MakeIcns.showDialog(self,window)
            
    def showDialog(self,window):
        dlg = QDialog(window)
        dlg.setFixedSize(250,100)
        label = QLabel('This file is invalid.\nPNG file[2048*2048,72dpi] required',dlg)
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        label.move(15,20)
        label.setStyleSheet('font-size:14px')
        btn = QPushButton("OK",dlg)
        btn.move(90,60)
        def action():
            dlg.close()
        btn.released.connect(action)
        dlg.setWindowTitle("Attention")
        dlg.exec()