MCLAダウンロードページ

鐵火卷です。

MCLAダウンロードページへようこそ。
ここではMCLAのプロト版をダウンロードできます。

以下の「mcla_proto」を押すことでダウンロードできます。

mcla_proto
※ ダウンロード容量: 約17MB
※ セットアップ時にダウンロードが行われ、100MB近くまで増えます。

 

ダウンロード後は適当な場所に配置・解凍してください。
自前の環境では日本語の入ったディレクトリでも正常に導入、起動することが出来ました。

詳細は以下の動画を。

 

軽く説明すると、

  1. 「setup.bat」を実行。
  2. 必要があれば「p_setting.ini」の「index_decive」を変更。
  3. 「run_MCLive.bat」を実行
  4. OBSなどで適宜クロマキーの設定。

こんな感じで行ける。

ロゴ

MCLAのロゴ

YouTube、Twitchなどでロゴを利用したい場合は使用して下さい。

その他、何か異常があれば動画コメント、もしくはこの記事のコメントに書き込んでください。

【waifu2x】立ち絵などのpsdファイルを半自動で拡大するツールを作ってみた

こんにちは、鐵火卷です。

今回はwaifu2x-coffeに.psdファイルを処理させてあげるツールを作成した+紹介動画も作りましたので、その記事です。

追加情報や細かい話などは後々追加していきます。

サポート


ソースコード


何はともあれ、.psdファイルをwaifu2xで拡大する、という需要を教えてくれたしはぶき様には再度御礼申し上げます。ありがとうございました。

しはぶき様の動画で、waifu2xは詳しく説明されています。
waifu2xについて知りたい方はぜひご覧ください。
↓そのしはぶき様の動画

「psd2waifu2x」ソースコード

これらのソースコードは改変などは基本的に自由に行ってもらって構いません。
ただ、改善や機能追加等をして頂けた場合は、僕自身興味がありますのでコメント欄などにご一報いただけると幸いです。


psd2wife.py


#coding:utf-8

from psd_tools import PSDImage
import os, copy, subprocess, datetime, glob, sys
from configparser import ConfigParser

class PSDPaser:
    def __init__(self, dir_psd, dir_cfg = os.path.join(os.path.dirname(__file__), "psd2wife.ini"), safe_mode = True):
        self.config = ConfigParser()

        self.config.read(dir_cfg, "utf-8")
        self.wf_scale = float(self.config.get("waifu", "wife_scale"))
        self.dir_safe = self.config.get("save", "safety")

                
        self.dir_psd = dir_psd
        self.psd = PSDImage.open(dir_psd)

        self.psd_all = [i for i in self.psd.descendants()]
        
        if safe_mode:
            self.dir_save_base  = os.path.join(self.dir_safe, datetime.datetime.today().strftime("%Y%m%d_%H%M_%S"))
        else:
            self.dir_save_base = self.dir_psd.replace(".psd", "")
        self.dir_save_pics  = os.path.join(self.dir_save_base, "result") 
        
        list_file_name = []
        
        structure = []
        structure_all = []
        structure_hrchy = []
        
        structure_safe = []
        structure_safe_all = []
        structure_safe_hrchy = []
        psd_setting=[[str(int(self.psd.width * self.wf_scale)), str(int(self.psd.height * self.wf_scale))]]
        
        print("「{}」\nに.psdの各レイヤーを画像に変換します。".format(self.dir_save_pics))
        for psd_elem_num, psd_elem in enumerate(self.psd_all):
            if str(psd_elem.parent.name) == "Root":
                structure = []
                
            loop=0
            structure = []
            structure_safe = []
            
            psd_group = copy.deepcopy(psd_elem.parent)
            while psd_group.is_group():
                loop+=1
                structure.append(psd_group.name)
                if str(psd_group.name) != "Root":
                    psd_group = psd_group.parent
                else:
                    break
            try:
                structure.remove("Root")
            except:
                pass
                
            file_name = psd_elem.name
            list_file_name.append(file_name)
            
            if safe_mode:
                for i in structure:
                    if structure_all.count(i) == 0:
                        structure_all.append(i)
                    structure_safe.append("Group_{}".format(str(structure_all.index(i)+1)))
                for i in structure_safe:
                    if structure_safe_all.count(i) == 0:
                        structure_safe_all.append(i)
            
            if structure_hrchy.count(structure) == 0 and structure != []:
                structure_hrchy.append(structure)
                
                structure_safe_hrchy.append(structure_safe)
                
            if safe_mode:                
                structure = structure_safe
                file_name = "layer_{}".format(str(psd_elem_num+1))
                
            os.makedirs(os.path.join(self.dir_save_pics, *structure[::-1]), exist_ok=True)
            dir_save = os.path.join(self.dir_save_pics, *structure[::-1], file_name + ".png")
            psd_setting.append([dir_save, str(int(psd_elem.offset[0] * self.wf_scale)), str(int(psd_elem.offset[1] * self.wf_scale)), "_".join([*structure[::-1], file_name]), str(int(psd_elem.is_visible())), structure[0] if structure != [] else "this_is_base_group"])
            if not psd_elem.is_group():
                try:
                    layer = psd_elem.topil()
                    layer.save(dir_save)
                except:
                    print("{}は保存されませんでした。".format(psd_elem.name))
                    
        self.gimp_structure_all = "[\"{}\"]".format("\",\"".join(structure_all))
        self.gimp_structure_hrchy = "[{}]".format(",".join(["[\"{}\"]".format("\",\"".join(i)) for i in structure_hrchy]))
        self.gimp_structure_safe_all = "[\"{}\"]".format("\",\"".join(structure_safe_all))
        self.gimp_structure_safe_hrchy = "[{}]".format(",".join(["[\"{}\"]".format("\",\"".join(i)) for i in structure_safe_hrchy]))
        
        self.gimp_file_name = "[\"{}\"]".format("\",\"".join(list_file_name[::-1]))
                
        print("変換終了")
        str_ = "\n".join([",".join(i) for i in psd_setting])
        self.dir_save_setting = self.dir_save_pics+".txt"
        with open(self.dir_save_setting, "wt") as f:
            f.write(str_)

        
    def waifu_run(self):
        dir_waifu = self.config.get("waifu", "directory")
        try:
            cmd="\"{}\" -i \"{}\" -s {} {}".format(dir_waifu, self.dir_save_pics, str(self.wf_scale),self.config.get("waifu", "setting"))
        except:
            cmd="\"{}\" -i \"{}\" -s {}".format(dir_waifu, self.dir_save_pics, str(self.wf_scale))
        print("「{}」を実行します。しばらく時間が借るので放置してください。".format(cmd))
        subprocess.call(cmd)
        
    def gimpImportCommand(self):
        dir_converted = glob.glob(self.dir_save_pics+"*"+ os.sep)
        os.rename(self.dir_save_pics, self.dir_save_pics+"_preWaifu2x")
        os.rename(dir_converted[1], dir_converted[0])
        
        dir_save_gimp_cmd = os.path.join(self.dir_save_base, "gimp_cmd.txt") 
        dir_save_gimp = self.dir_save_setting.replace(".txt", ".xcf")
        gimp_cmd='''import codecs
dir_txt = r"{}"
dir_save = r"{}"

structure_all = {}
structure_hrchy = {}
structure_safe_all = {}
structure_safe_hrchy = {}

gimp_file_name = {}

with codecs.open(dir_txt, 'r', 'utf-8', 'ignore') as f:
    im_setting = f.read()

list_ims = [i.split(",") for i in im_setting.split("\\n")]
image = gimp.Image(int(list_ims[0][0]), int(list_ims[0][1]), RGB)

list_group=[pdb.gimp_layer_group_new(image) for i in structure_safe_all]

for i in range(len(list_group)):
    #list_group[i].name = structure_safe_all[i]
    list_group[i].name = structure_all[i]

base_group = []
list_hierarchy = []
for i in range(len(structure_safe_hrchy)):
        if len(structure_safe_hrchy[i])>1:
            list_hierarchy.append(structure_safe_hrchy[i])
        else:
            base_group.append(structure_safe_hrchy[i])

base_group = base_group[::-1]
list_hierarchy = list_hierarchy[::-1]
for  i in range(len(base_group)):
    image.add_layer(list_group[structure_safe_all.index(base_group[i][0])], i)


list_remove = []
for i in range(len(list_hierarchy)):
    test = list_hierarchy[i][::-1]
    if len(test)>1:
        for j in range(len(test)-1):
            check=[test[j+1], test[j]]
            if not check in list_remove:
                list_remove.append(check)
                group_check = [list_group[structure_safe_all.index(check[0])], list_group[structure_safe_all.index(check[1])]]
                pdb.gimp_image_insert_layer(image, group_check[0], group_check[1], i)
                print(check)

gimp.Display(image)

for num_setting in range(len(list_ims[1:][::-1])):
    layer_setting = list_ims[1:][::-1][num_setting]
    try:
        layer = pdb.gimp_file_load_layer(image, layer_setting[0])
        layer.set_offsets(int(layer_setting[1]), int(layer_setting[2]))
        layer.name = gimp_file_name[num_setting]
        pdb.gimp_drawable_set_visible(layer, int(layer_setting[4]))
        
        key = layer_setting[5].replace("\\r","")
        gimp.message(key)
        if key == "this_is_base_group":
            image.add_layer(layer, num_setting)
        else:
            pdb.gimp_image_insert_layer(image, layer, list_group[structure_safe_all.index(key)], num_setting)

    except:
        pass

drawable = pdb.gimp_image_get_active_layer(image)
pdb.gimp_xcf_save(0, image, drawable, dir_save, dir_save)

gimp.Display(image)

'''.format(self.dir_save_setting, dir_save_gimp, self.gimp_structure_all, self.gimp_structure_hrchy, self.gimp_structure_safe_all, self.gimp_structure_safe_hrchy, self.gimp_file_name)


        with open(dir_save_gimp_cmd,"w",encoding="utf-8") as gimp_file:
            gimp_file.write(gimp_cmd)
        subprocess.run("explorer {}".format(self.dir_save_base))



if __name__=="__main__":
    print("グループ名が重複しているとバグが発生して正常に変換できません。\n手動でPSDファイルを編集して、グループ名が重複しないようにリネームしてください。\n(例: 「Group」→「Group #1」)")
    print("もしくは1度Gimpでpsdファイルを開き、再エクスポートしてください。\n重複が自動で解決されます。")
    dir_psd = input("waifu2xで変換したい.psdファイルをD&DしてEnterを押してね!")
    psdp = PSDPaser(dir_psd)
    psdp.waifu_run()
    psdp.gimpImportCommand()

psd2wife.ini


[save]
safety=G:\Dev_Doc\gimp
[waifu]
directory   = O:\files\waifu2x-caffe\waifu2x-caffe-cui.exe
wife_scale  = 2.0

psd2waifu2x配布・サポート(?)ページ

こんにちは、鐵火卷です。

このページは先日公開いたしました「psd2waifu2x」の配布、サポートページとなっています。

配布

「psd2waifu2x」は以下のonedriveよりダウンロード可能です。
https://1drv.ms/u/s!AsMZ4BamVPJEgTMsrM3wn266tDUT

また、別ページのソースコードをコピペして使用してください。

動作環境

windows (10でのみチェック)
Python 3.x系列 (3.7でのみチェック)
Gimp (インストール版でのみチェック)
waifu2x-coffee

使い方

動画を参照してください。

サポート

困ったことがあれば、コメント欄に記載していただければと思います。
ただし、以下の内容についてはお答え出来かねます。

・動作確認など(特に、このスペックで動作しますか?といった質問)
・GUI作って!
 → 初学者なので現状は無理です。数年後 or 別の人に頼んでください。
・ポータブルにしてほしい!
 →ironpythonとgimpのポータブルとかでも行けるんですかね?誰か検証してください。
・Gimpのpython上ですべて完結すればいいのでは?
 →gimpで日本語のファイルとディレクトリを扱えるようにする手段をだれか教えてください…

FAQ?

Q1. グループ名が被っているとGimpでの再構成でエラーが出る
A1. Gimpで一度.psdファイルを開き、.psdとしてエクスポートしてください。
Gimpは同じ名前のグループ、レイヤーを作成することが出来ません。
ですので、.psdファイルを開くだけで自動的にリネームしてくれます。

Q2. Gimpでレイヤーが読み込まれない
A2. 保存先として設定したディレクトリに非アスキー文字が含まれているためです。
ディレクトリに半角英数しか含まれていないことを再度確認してください。
場合によっては半角スペースもエラーの原因かもしれません。

Q3. Pythonのプログラムでエラーが出る。
A3. それ、Pythonの2.x系列じゃないよね?
あと、要求されるモジュールもインストールしてね。
場合によってはpipのアップデートが出来てないのかも?

FFMPEGで扱える画像の最大解像度について…

鐵火卷です。技術メモ。

FFMPEG触ってて、訳があってかなり大きな画像を読み込ませようとしたとき、解像度のエラーが出ました。

具体的には、2700×143600だとエラーが出て、2900×28500だと可能でした。
3000×30000までならいけるんでしょうか?

今は2900×30200くらいに分割して使用していますが、現状エラーは出ていません。

参考までに。
どなたか、具体的な最大解像度をご存知でしたらお教えくだされば幸いです。

それでは。

名前が「鐵火卷 」になります。

お久しぶりです。クロガネです。

個人的な趣味趣向により、名前が「鉄火巻」から旧字体の「鐵火卷」に代わります。
旧字体もいいよね、ってことで変わることにしました。

書けないんだけどね。
そこまで複雑ではないので練習してかけるようにしておこう。

 

それでは、クロガネでした。

 

Blender2.8のPythonにモジュール類を簡単に移行するには

こんにちは、鉄火巻です。

前の記事では、Blender内のPythonにモジュールをインストールする方法を紹介しました。

ここでは、通常のPyhtonで使っているモジュールをBlenderに移行するとき、バージョンなどを指定しながらいちいち移していく面倒を解決する方法です。
といっても、よくあるやり方です。

手順

これはシンプル。まずは、通常のpythonの環境から各種モジュールのバージョンを記載したテキストファイルを生成しましょう。

python -m pip freeze > requirement.txt

生成先は指定できるので、取り出しが面倒であれば、直接Blenderのあるフォルダに生成してあげましょう。

python -m pip freeze > "O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin\requirement.txt"

次に、cd, cd/dなどで移動して、

cd/d  
O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin

pipからインストールしましょう。
前の記事でも書きましたが、Blender側からモジュールを読み込むには–userのオプションが必須です。

 python.exe -m pip install -r requirements.txt --user 

以上です。特に難しいってわけではなさそうだね。

それでは、鉄火巻でした。

Blenderに搭載されているPythonにpipを導入しよう(Windows10, ポータブル版)

こんにちは、鉄火巻です。

最近Blenderを触っているんですが、外部のモジュールをどうしても使いたいのでpipを導入しようと思います。といっても、参考サイトとやってることは同じだし、特に変なことはしていません。

手順

以下をcmdで実行しましょう。管理者権限はあった方がいいんじゃないかな? Blender2.8を使用しているため、ディレクトリはProgramfileではありません。いわゆるポータブル版です。 インストーラーを使ってインストールすればProgramfileのどこかに同じようなフォルダがあるでしょう。

 "O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin\python.exe" -m ensurepip

すると以下のようにpipとsetuptoolsがインストールされます。ただし古いバージョンです。

C:\WINDOWS\system32>"O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin\python.exe" -m pip list
Package Version
---------- -------
pip 10.0.1
setuptools 39.0.1

ですので、以下のようにそれぞれアップデートしてあげましょう。これも特に変わったことではありません。

 "O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin\python.exe" -m pip install --upgrade setuptools pip

これで最低限pipはインストールできました。pythonから環境を移行するときは以下のように主環境でrequests.txtを生成してやればよいでしょう。

この辺のモジュール(https://qiita.com/haminiku/items/5187713bba6cb30532bf)を入れておくと便利でしょう。

注意) –userのオプションが必要

pipの触り方は以上のように、Blender内のpythonを直接たたけばよいのですが、以下のようにモジュールをインストールすると、Blenderからimportする時にエラーを吐きます。

".../python.exe" -m pip install [module name]

調べたところ、インストールには–userのオプションが必要です。面倒ですが、毎回、以下のようにインストールしましょう。

 ".../python.exe" -m pip install [module name] --user

参考

https://www.kunihikokaneko.com/dblab/cg/bpypip.html

https://blenderartists.org/t/how-to-install-python-packages-with-pip-blender-2-8/1142721/3

余談

当たり前ですけど、以下からpythonのバージョンは確認可能です。

 "O:\files\blender-2.80.0-git.99d4321feff6-windows64\2.80\python\bin\python.exe" -V

多分ですけど、主環境と同じpythonが入るみたいですね(ポータブルだからかな?)。僕の環境では3.7.0って返ってきました。


以上です。pipがあれば開発が捗りますね。 必要なモジュールが入れば開発の幅は一気に広がりますね。

それでは、鉄火巻でした。

関連記事

最近の投稿など。

やあ、鉄火巻だ。

ブログも長らく放置していたね。更新がなかったけど色々はやってたんだ。


実況動画投稿

まず、エアライドの動画をアップロードしました。大した動画ではないけどね。
動画にも書いているけど、一応、シティトライアルの速度が「普通」の設定でランキングに入るくらいのスコアは出てるんだ。

ランキング的には13位?でも普通部門が出来た上、参加者が少ないので、まだランカーとは言えないんだ。だから自称ランカーって書いたんだ。

一緒にプレイしたみりん君は昔からの中ですが、基本的に据え置き機はプレイしていないそうです。なので、完全に初心者です。確かに、エアライドのマシン操作って割と面倒だよね。僕もライトスター以外制御できないし。まあ、今後上手くなっていくといいな、と。

これはitch.ioで遊べるブラウザゲーです。確か、ダウンロードして遊ぶこともできたような?

YouTube側では結構前に投稿してたんだけど、これは「Pogostuck」っていう超高難易度の壺おじ系ゲームが某所で有名になったので、一応ニコニコにもアプロードしよう、ってことになったんだね。まあ、自己満足さ。

PUBG

実は大半の時間はPUBGに使ってたんだ。といっても、1日平均1.5時間くらいだね。まあ、ゲームのプレイ時間としては平均的だね。

そもそも初のTPS/FPSみたいなもんだったので、かなり弱いのです。なんせ、ドン勝もスクアッドで6回、ソロはまだだしね。まあ、ぼちぼちやっていくよ。

他のメンバーはPUBGをプレイできる環境でないので、動画は上がらんでしょう?多分ね。

開発など

この辺はじわじわ進んでいます。動画編集を楽にするために動画十本分くらいの編集時間を捧げている感じだね。アホす。というか、情報が少なすぎてワロタwwwって感じだね。


まあ、ほぼほぼ活動してないけど、これはこれで楽しいね。
さて、来年度からどれだけ活動出来ることやら…

それでは、クロガネでした。