人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

【Unity】csv読み込みとObjectsへの画像貼り付け

 

本記事はDEMO動画にある、

「Unity+AIを用いた手書き数字識別システム」の実装方法について説明する。

前回の記事  

www.hiro877.com

 


 

 

本記事のテーマ

「csv読み込みとObjectsへの画像貼り付け」

を実装する。

下記DEMO動画内の1:34付近。

CSVから読み込んだ画像データをPlaneObjectsに貼り付ける処理

Demo


www.youtube.com

 

実装動画

本記事の実装を録画した動画です。


www.youtube.com

 

 

実装環境

  • Ubuntu20.04
  • UnityHub2.4.2
  • Unity 2019.4.21f1

 

ソースコード

Githubで管理

・paste-images-into-planeブランチ

ブランチの切り替えは下記画像の赤枠をクリックして変更できる。

f:id:hiro-htm877:20210502170814p:plain

github.com

 

 

CSVの読み込み

今回はResources.Load(file_path)で行う。

TextAsset csv = Resources.Load(file_path) as TextAsset;

この関数はAssets/Resourcesディレクトリ内のファイルをResourcesディレクトリ内からの相対パスで検索します。

ですので、まず、Assets下にResourcesディレクトリを作成してその中に読み込みたいファイルを配置してください。

今回はMNISTの手書き数字をもちいます。

GithubのAssets/Resourcesにfor_saving.zipという名前で置いていますのでDownloadしてご使用ください。 

Unity-htm.core-MNIST/Unity-Learning-MNIST/Assets/Resorces at paste-images-into-plane · hiro877/Unity-htm.core-MNIST · GitHub

下記関数でコンマ区切りのCSVファイルが読み込める。

行っていることは文字列(数字)のCSVデータを1行づつ読み込んで、Byte型に変換し、1行づつの2次元配列を作成しています。

※今回用意したデータは28*28=784このデータが30行分です。

csvReaderPlaneImages = read_mnist_images(csvReaderPlane_imeges_path);
 
List<List<byte>> read_mnist_images(string file_path)
{
TextAsset csv = Resources.Load(file_path) as TextAsset;
StringReader reader = new StringReader(csv.text);
List<List<byte>> data = new List<List<byte>>();

while(reader.Peek() != -1)
{
string[] str_line = reader.ReadLine().Split(',');
List<byte> line = new List<byte>();
foreach(string str in str_line)
{
line.Add(byte.Parse(str));
}
data.Add(line);
}
return data;
}

 

CSVデータ(1次元)から画像データ(2次元)へ変換

引数に1次元のList<byte>をとり、縦28, 横28のList<List<byte>>に変換して返します。

List<List<byte>> convert_data( List<byte> data_array,
bool is_texture_axis=false)
{
List<List<byte>> d = new List<List<byte>>();
for (int i = 0; i < IMG_HEIGHT; i++) d.Add(new List<byte>());
 
for(int y = 0; y < IMG_HEIGHT; y++)
{
for(int x = 0; x < IMG_WIDTH; x++)
{
if (is_texture_axis)
{
d[IMG_HEIGHT - y -1].Add(data_array[y * IMG_HEIGHT + x]);
}
else
{
d[y].Add(data_array[y * IMG_HEIGHT + x]);
}
}
}
return d;
}

 

画像(List<List<byte>>)をPlaneObjectsに貼り付ける

List<List<byte>>をTextureに変換してObjectsに貼り付けます。

まずはデータを一つずつColorクラスに変換してSetPixelでattach_textureに追加していきます。

attach_texture.Apply()でSetPixelで追加したデータがTextureに反映されます。

最後に貼り付けたいtargetオブジェクトのmainTextureに代入して完了です。

public void AttachImage(GameObject target, List<List<byte>> byte2D,
int width, int height){
Texture2D attach_texture = new Texture2D(width, height);

for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
attach_texture.SetPixel(x, y, new Color(byte2D[y][x], byte2D[y][x], byte2D[y][x]));
}
}
attach_texture.Apply();
target.GetComponent<MeshRenderer>().material.mainTexture = attach_texture;
}

 

 

 Spaceキーで画像を表示

今回はわかりやすいために、Spaceキーを押したときに画像が出来るようにしました。

void Update()
{
if(Input.GetKey("space")){
Debug.Log("Pushed Tab");
if (!testDisplayFlag){
List<byte> img = csvReaderPlaneImages[0];
List<List<byte>> img_byte2D = convert_data(img, true);
AttachImage(csvReaderPlane, img_byte2D, IMG_WIDTH, IMG_HEIGHT);
testDisplayFlag = true;
}
}
}

 

ソースコード

 

 

 

 

 

▶クリックでソースコードを展開
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class SmallCubeDirector : MonoBehaviour
{
    // Fungus
    public Fungus.Flowchart flowchart = null;

    // Display Test Image
    public GameObject csvReaderPlane;
    private List<List> csvReaderPlaneImages;
    private string csvReaderPlane_imeges_path = "test_images30";
    private bool testDisplayFlag = false;

    // MNIST Image
    private const int IMG_WIDTH = 28;
    private const int IMG_HEIGHT = 28;

	void Awake() {
        csvReaderPlane = GameObject.FindGameObjectWithTag("csvReaderPlane");
	}

    void Start()
    {
        csvReaderPlaneImages = read_mnist_images(csvReaderPlane_imeges_path);
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey("space")){
            Debug.Log("Pushed Tab");
            if (!testDisplayFlag){
                List img = csvReaderPlaneImages[0];
                List<List> img_byte2D = convert_data(img, true);
                AttachImage(csvReaderPlane, img_byte2D, IMG_WIDTH, IMG_HEIGHT);
                testDisplayFlag = true;
            }

        }
        
    }

    public void StartFungus(string message){
        flowchart.SendFungusMessage(message);
    }
    public void StartFungusFromEventPlane(){
        flowchart.SendFungusMessage("start_question");
    }

    List<List> read_mnist_images(string file_path)
    {
        TextAsset csv = Resources.Load(file_path) as TextAsset;
        StringReader reader = new StringReader(csv.text);
        List<List> data = new List<List>();

        while(reader.Peek() != -1)
        {
            string[] str_line = reader.ReadLine().Split(',');
            List line = new List();
            foreach(string str in str_line)
            {
                line.Add(byte.Parse(str));
            }
            data.Add(line);
        }
        return data;
    }

    List<List> convert_data( List data_array,
                                    bool is_texture_axis=false)
    {
        List<List> d = new List<List>();
        for (int i = 0; i < IMG_HEIGHT; i++) d.Add(new List());
        
        for(int y = 0; y < IMG_HEIGHT; y++)
        {
            for(int x = 0; x < IMG_WIDTH; x++)
            {
                if (is_texture_axis)
                {
                    d[IMG_HEIGHT - y -1].Add(data_array[y * IMG_HEIGHT + x]);
                }
                else
                {
                    d[y].Add(data_array[y * IMG_HEIGHT + x]);
                }
            }
        }
        return d;
    }

    public void AttachImage(GameObject target, List<List> byte2D,
                            int width, int height){
        Texture2D attach_texture = new Texture2D(width, height);

        for(int y = 0; y < height; y++)
        {
            for(int x = 0; x < width; x++)
            {
                attach_texture.SetPixel(x, y, new Color(byte2D[y][x], byte2D[y][x], byte2D[y][x]));

            }
        }
        attach_texture.Apply();
        target.GetComponent().material.mainTexture = attach_texture;
    }

}

 

 

 

 

 

 

 

 

以上で実装は終了になります。 

これでSpaceキーを押した後に画像がPlaneObjectsに表示されます。

 

 

もし、動かない場合はコメント欄にて報告して頂けますと助かります。


関連記事 

www.hiro877.com