;

西デザインコンサルティング

お問合せ

プロフィール

会社概要



プログラミングの何が楽しいの?具体例から楽しそうなところを探し出そう!



プログラミングの何が楽しいのでしょう?


「プログラミングを趣味にしよう!」と言っても、趣味は楽しくないと続かないもの。

では、プログラミングの何が楽しいのでしょう?

概念的に「何でも作れる」、「考えること」等が「楽しい」と言われても、

「楽しさ」は個人個人の考え方で変わるもの。一人が「楽しい」と考えても、他の人には「つまらない」ものもたくさんあります。

もう少し具体的に「楽しい」か「楽しくない」か、見極めることができれば、プログラミングを始めるきっかけになるかもしれません。

そこで私は、「販売できるソフトウェア」を目指して、Geasyoneという名前の画像処理ソフトを4カ月かけて開発し、その内容を公開することで、「どの部分が楽しそうと思えるか見て頂きたい」と考えました。

画像処理に詳しい人ならば知っていると思いますが、フリーソフトで有名なのがGIMP。高価ですが、有料ソフトで評価が高いのがPhotoshopです。

勿論、PowerPointにも画像処理機能が付いています。その中で、「販売できるソフトウェア」を開発して、実際に売れるとは思っていません。

でも「販売する」となると、優れた機能を搭載するだけではなく、使い勝手やセキュリティ、バグが無いソフト開発を目指す必要があります。

即ち、ソフト開発に必要な技術を全て考える必要があり、その技術を公開することで、その中のどの部分を「楽しい」と感じて頂けるか、検証することができると考えました。

では早速、その中身を見ていきましょう。項目は以下の通りです。

第1章 どんなソフトウェアを作るか?
第2章 どんな機能を搭載するか?
第4章 どのような見栄えにするか
第3章 ソフトウェア開発で必要なこと
第5章 webから探し出す
第6章 パッケージで考える
第7章 プログラミングの楽しさは「仕様と手順」から考えること
第8章 プログラミングの楽しさは「無いもの」を考えること

第1章 どんなソフトウェアを作るか?


ソフト開発で最も重要なことは、「何を作るか」です。

ソフトウェア開発会社に入社した場合、それぞれの会社に開発しているソフトウェアがありますので、その一部の担当者となり、そこにある課題をクリアしていくのが仕事となります。

でも、ソフト開発を趣味とする場合、他人に要求されるものではないので、「自分が何を作りたいのか?」が最も重要です。

「作りたいものはない」と言ってしまえばそれで終わりですが、「プログラミングを趣味にする」ことに少しでも興味があれば、自分の日常生活で使っているソフトやアプリについて、「自分でオリジナルのものを作ってみたい」と考えるのがベストです。

私の場合は、「ホームページを作成する」ために使っていた色々なソフトの使い勝手の悪さが、Geasyone作成の動機となりました。

昨年からホームページを立ち上げる作業を行ってきましたが、その資料作成は、PC上の画像やPCカメラの画像を加工して使う必要があります。

しかし、それぞれ別の市販ソフトを色々使っての作業となり、「面倒くさい」と感じていました。

また、画像加工ソフトも有料ソフトに毎月の使用料を支払うほど、常時使うものではなく、無料ソフトではほしい技術が無く、使わない技術が多く付いており、機構や使い方を覚えるのも大変で、自分にとって使い勝手が悪いという印象もありました。

そこで考えたのが、「全ての作業を1つのソフトでできないか?」「自分の使う技術のみ搭載して使い勝手を良くできないか?」でした。

そのような好奇心、欲求を満たすために作ったのが画像処理ソフトGeasyoneです。

この「どんなソフトを作るか?」で、その後の「楽しさ」も大きく変わってきます。「趣味」や「ほしいな」と思っていることを手助けしてくれるソフトウェアの作成ならば、「頑張ろう」と思う気持ちも芽生えるのではないでしょうか?

第2章 どんな機能を搭載するか?


作るソフトウェアが決まったら、次にどのような機能を盛り込むかです。欲しい画像はPCのインターネット上にあふれています。これを利用して資料を作成するには、画像データを取り込んでその一部を切り取って使用する、携帯の動画やWebカメラの動画の一部を切り取って使う機能はほしい。

そこで盛り込む主な機能としては、

① 動画(MP4,AVI,MPEG,MTS,WMV,FLVフォーマット)を再生し、画像を取り込む
② PCに設置されたPCカメラ、任意のWebカメラの画像を表示し、画像を取り込む
③ PC上に表示された動画から画像を取り込む
④ 180度、360度画像、3D画像(obj,stl,dxfフォーマット)を表示し、画像を取り込む

機能を考えました。単一ソフトだけで上記情報を取り出せるソフトやアプリは、私の知っている範囲では存在していなかったので、それを作成することに魅力を感じたのです。

但し、PC上の画像のコピーは著作権侵害となる可能性もあります。加工を行う場合でも、単純なトリミングやその画像が著作権として認められるような特徴を残す使い方は避けた方が良いと思います。

次に必要となるのが、取り込んだ画像の加工。私はアーティストではないので、取り込んだ画像に芸術を盛り込む必要はありません。よって、ペン先の色々な形状は考えず、以下の機能に特化しました。

① フィルター処理(明度、彩度、ガンマ補正、平滑化、エッジ強調)
② 画像消去、画像再現、エッジ抽出、歪曲、ペイント、文字表示
③ コピー、ペースト、画像合成
④ 透明線による切り取り、色による切り取り、エッジ抽出による切り取り
⑤ 画像の穴埋め、画像の連結、ノイズ除去
⑥ 解像度変更、画像部分抽出、回転・台形処理

上記は一般のフリーソフトでも行えることが多いです。でも、ソフトはそれぞれの用途に応じて、多用する機能が異なります。「自分にとって使い易くする」それが大きな課題です。

更に、その機能を実現するためには、どのようなアルゴリズムにするか?基本的な技術を調べ、それをソフトとして具現化するのが、私にとってソフトウェア作りの一番楽しいことに感じられました。

最後の機能が、他のソフトとの相性、見栄え、その他となります。

① 分かり易い、操作入力手段の配置
② 使い勝手の良い入力手段の配置
③ Windowsソフトとのコピー・ペースト処理の容易性
④ 操作手順の表示
⑤ セキュリティに対する対応
⑥ 色々なテストでバグが発生しないこと
⑦ 各処理の処理速度、スムーズさ

実は上記が最も時間がかかる部分。会社でのソフト開発、市販を目的としたソフト開発では上記の項目を無視することはできません。6~7割がこの作業です。

単純な反復作業と、コピペした部分、即ち、他人が作成したソフトの読解、欲しい機能に作り替える時のデバッグ作業等です。これだけの作業を行っている人は「ソフトウェア開発が辛い」と感じてしまうかもしれません。

しかし、自分だけのオリジナルソフトを作るだけなら、この最も面倒な部分をやらずに済みます。

このように、ソフトを開発する際、「どんな機能を盛り込むか?」を大雑把に決めます。私はこれを「できるかな?無理かな?」と考えながら構想検討するのが楽しかったです。

第3章 ソフトウェア開発で必要なこと


開発したいソフトウェアの内容が決まったら、どんなプログラミング言語を使うかです。これはこのホームページの「趣味なら、プログラミング言語は?」で説明しましたが、推奨はc#とExcelのVBAです。

C#はWindowsのOSが入っているPCで、VisualStudioをインストールすることで入手できます。インストールは無料です。

ExcelはWindowsのOSが入っているPCで、Excelを購入する必要がありますが、PC購入の際、Word、Excel、PowerPointはセットで入っていることが多いので、「ソフトを趣味に」と考える人ならば、使ったことがあると思います。

ソフトの開発環境が構築できると、次にソフトを作ってみたくなると思います。最も簡単な実現方法がプログラミングスクールに通う事。最近はオンラインでも講習を受けることができます。

でも、「プログラミング学習を独学で行いたい」と考えるならば、PC上での検索を行い、分かり易く解説しているサイトを見つけ出すことが重要となります。

例えば、上記VisualStudioのインストール方法などは、「c# インストール」のキーワードで検索すれば、数多くのサイトで紹介しています。その中の分かり易いサイトの手順に沿って作業をするだけ。直ぐにソフトウェア開発環境が構築できます。

次はそのプログラミング言語の勉強。これもPC上での検索で「c# 入門」のキーワードで検索すれば細かい使い方を説明してくれています。

これらを行った後で、やっと「ソフト開発」に着手できるようになります。

上記作業を「大変だ」と思わない人は「独学でソフト開発」を行うことをお勧めします。PCの検索内容を色々比較して、「どの記述に沿って作業してくか」を考えることも学習の一つで楽しいからです。

一方、上記内容に沿ってPCで用語を検索しても、その内容は専門用語の羅列であり、「比較するどころか、1つを読むだけでも大変」という方もいらっしゃると思います。そのような場合は、プログラミングスクールに通うのが近道です。

理由は、PCの膨大な情報から必要な情報を検索するのも一苦労なので、そこで挫折してしまっては、プログラミングの面白さまで到達できずに終わってしまう可能性が高いからです。プロに色々習い、逐次分からない部分を教えてもらって進むのがベストです。

残るのはオンライン講習。弊社でもこれに類似したサービスを提供していますが、ある程度、Excelの表計算やWordの文章作成、Web検索を行った経験があるが、ソフト作成についての経験があまりない人向けです。

オンライン講習の場合、PC画面に向かって講習をしてもらう、メールを使って質疑応答をしながらソフト作成を行っていきます。PCを使い慣れていないとそのやり取りだけで疲れてしまう可能性が高いですから。

オンライン学習の良いところは、任意の時間を使って、手軽に自宅でできること。

特に質疑応答をメール等でやり取りできる環境が整っていれば、自分のスケジュールで空いている時間を使った、チャットのようなやり取りも可能です。

facebook等を使い、作成したソフトの発表会等で趣味が共通のメンバー同士の交流も面白いと思います。

このように、プログラミングを趣味にする場合は、自分の今持っているノウハウに応じてソフトの勉強を始め、モチベーションを高めるのが長続きの秘訣です。

第4章 どのような見栄えにするか


ではいよいよc#で作ったGeasyoneを使って、その内容を見ていきましょう。

Geasyoneは起動すると以下のような画面が表れます。最も多く使用するのは静止画の取込やPowerPointのコピー画像なので、それらを簡単に取り込めるようにしました。

Geasyone表示


使用頻度の低い動画、webカメラ、PC画像の取込は上のメニューから選択します。右の広い空白部分は画像出力・加工部という構成です。

c#はGUIが優れているので、情報をインプットする手段がたくさんあります。それを使い易くするためにどのような手順で表示していけば良いか、それは作成者の好みで決めることができます。

以下は、このソフトで表示される各機能のデザインを全て表示したデザイン図です。機能毎にまとめたGroupBoxを、必要に応じて表示・非表示、位置変更をします。大別には上のToolStripMenu等を使います。

c#はエディター上のツールボックスにある、これらのツールを作業画面上にペーストするだけで、このような入出力手段が簡単に作れます。

Geasyone機能


例えばエディター上で作られたボタンをクリックすると、プログラミングの画面に切り替わります。ソフト起動時は、そこで書き込んだプログラミングがそのボタンを押すと実行されるのです。

GeasyoneGUI


自分にとって最も重要なのは使い勝手。よく使う指令を大きなボタンにしたり、色を変えたり、文字を大きくしたりできます。文字の代わりに画像を使うことも可能です。これらは全てボタンをクリックしたときに表示されるプロパティから変更できます。

ここではボタンを代表して説明しましたが、他にも色々な情報入力手段があります。これらはツールボックスで選択でき、これらを総称でコントロールと呼んでいます。コントロール毎にプロパティが存在しており、好みの色や大きさに変更可能です。

この見た目を簡単にカスタマイズできるところが、c#の楽しさの一つです。

第5章 webから探し出す


では、そのプログラミングの中身を見てみましょう。c#は「オブジェクト指向型」のプログラミングと言われています。オブジェクト指向型については、以下のmicrosoft社のWebで確認ができます。


そこから引用すると、4つの基本原則は

① 抽象化 関連する属性とエンティティの相互作用をクラスとしてモデル化し、システムの抽象表現を定義します。
② カプセル化 オブジェクトの内部の状態と機能を非表示にして、公開されている一連の関数を通じてのみアクセスを許可します。
③ 継承 既存の抽象化に基づいて新しい抽象化を作成する機能。
④ ポリモーフィズム 複数の抽象化の間で、継承されたプロパティまたはメソッドをさまざまな方法で実装できます。

難しそうですよね?では、c#のプログラミングを趣味とする人に、上記のような詳細は理解する必要はあるでしょうか?

実際は全くありません。言葉も覚える必要はありません。

理由は簡単。上記考え方は、複数人でソフトを開発する時に意味があります。個人でc#を使う時は、必要な「オブジェクト指向型」の機能だけを使わせて頂き、詳細まで考える必要は無いからです。

では「機能を使う」とはどういうことでしょうか?

例えばc#の計算式ですが、四則計算(+-*/)と、剰余(%)しか使えません。でも色々計算する時に、絶対値:|―5|、累乗:2の5乗、ルート2、三角関数:sin30、cos30等、中高生で習った計算式も使いたい場合があります。

ここで利用するのが、他人が作ったオブジェクト指向型のclass。使い方は簡単。

プログラミングの頭に、

using System

と入れるだけ。これでmicrosoft社が提供しているMathというclass関数が使えるようになります。ここでSystemはMath関数が存在する場所を指し、「名前空間」と言います。

通常はSystem.Mathと記載しますが、usingで宣言すればSystemを省略できます。

上記計算は
Double a = Math.Abs(-5);
Double a = Math. Pow (2, 5);
Double a = Math. Sqrt (2);
Double a = Math. Sin(30*Math.PI/180);
Double a = Math. Cos(30*Math.PI/180);

で変数aに答えが返ってきます。このように、計算式を使う側にとっては、計算ができれば良い訳で、その中身がどのような計算をしているか、全く考える必要はありません。ブラックボックスで良いのです。これがオブジェクト指向型の②カプセル化という特徴です。

このMath classは1例に過ぎず、Geasyoneでは、以下のように、「名前空間」を指定して、データの取込等、数多くのclass関数を利用させて頂いています。

using Microsoft.Office.Core;//PowerPointへのコピー
using Microsoft.Office.Interop.PowerPoint; //パワーポイントのExport用
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D; //LineCap(矢印)の使用
using System.Drawing.Imaging;
using System.IO; //StreamReaderの使用
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Drawing.Point;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using System.Diagnostics;

どのような機能があるかは、Web上で「c# 用途に応じたキーワード」を入力するだけ。

各用途のclassが紹介されていますので、ソースコードのコピー&ペーストでまず簡単な動作確認を行います。上手く行きそうならば、自分のプログラミングの用途に合わせてモディファイしていきます。

この作業は検索による発見と、モディファイして自分のソフトに新機能を取り入れる楽しさがあります。

第6章 パッケージで考える


次に便利なのがパッケージの考え方。順を追って具体例を使い、説明していきましょう。

以下の例はゴルフが好きな太郎君。ゴルフのスコアをアプリで管理していたのですが、入力する項目が少なく、不満を持っていました。

そこでexcelの表計算を使って以下のような表を作り、コースに行った結果を入力、セルに計算式を入れ、ハンディキャップ等を計算、コースに行った後はエクセルのシートを増やし、次々に表をコピーしては記録、という作業を繰り返して管理していました。

エクセル管理表


最近、還暦を過ぎ、家にいる時間が増え、暇つぶしにPCを使った何かをできないかと考え、昔少し勉強したプログラミング(FORTRAN)を思い出し、「このExcelのゴルフスコア管理をプログラミングで作ろう」と決心しました。

エクセルのように、入出力が簡単で、バリエーションが豊富なc#に目を付け、実際に作業を始めたのです。

でも昔のFORTRANという言語に「オブジェクト指向型」の発想はありません。とりあえず、上記usingとclass関数の使い方と、使う変数の宣言方法だけ覚え、プログラムを作ってみることにしました

使用するのは配列とサブルーチン。For文やif文。これは書き方が少し違うだけで、考え方は全くFORTRANとc#で共通です。

文章を入れる部分はString。数字は整数がint,実数float,使用する変数の名前をローマ字、英語書きにして以下のように宣言します。//はコメント文でプログラムに影響がありません。式の説明を書いておき、後で何をするプログラミングか理解し易くします。

//宣言文publicは何処からもアクセス可能、配列数1000はコース1000回分
//1次元配列は *[]、2次元配列は*[,]のように使います
public string [] basho = new string[1000];
public string [] tenki = new string[1000];
public string [] kaze = new string[1000];
public string [] komento = new string[1000];
public string [] hansei_bun = new string[1000];
//コースのホール毎に情報があるものは2次元配列18はホール数
public int [,] par = new int[1000, 18];
public int [,] score = new int[1000, 18];
public bool [,] fairway = new bool[1000, 18];
public int [,] putt = new int[1000, 18];
public int [,] bunker = new int[1000, 18];
public int [,] approach = new int[1000, 18];
public int [,] shot = new int[1000, 18];
public float [,] OB = new float[1000, 18];
// handicap~score_sumの結果10個をResultに格納
public float[,] Result = new float[1000, 10];
//サブルーチン
//データ入力サブルーチンcountはコース回数。privateはここだけで使う宣言
private int input_data()
{
    //データ読み込み処理シーケンス記入。エクセルから入力予定?
    return count; //読み取れたコース回数
}
//データ入力サブルーチンint countはコース回数の引数
private void output_data(int count)
{
    //Resultの値を画面上に出力する処理シーケンス記入
}
//各計算サブルーチン int countはコース回数の引数、それぞれの計算式を入れる
private float handicap(int count)
{ return 計算式;}
private float par_on(int count)
{ return 計算式;}
private float bogy_on(int count)
{ return 計算式;}
private float fairway_keep(int count)
{ return 計算式;}
private int shot_miss(int count)
{ return 計算式;}
private int approach_miss(int count)
{ return 計算式;}
private int putt_sum(int count)
{ return 計算式;}
private int out_sum(int count)
{ return 計算式;}
private int in_sum(int count)
{ return 計算式;}
private int score_sum(int count)
{ return 計算式;}
//実行文 ボタン1が押された場合に計算
private void button1_Click(object sender, EventArgs e)
{
    //kaisuuはゴルフに行った回数
    int kaisuu = input_data()
    for (int i = 0; i< 1000; i++)
    {
        //サブルーチンの記述方法
        Result[i,0] = handicap(i);
        Result[i,1] = par_on (i);
        Result[i,2] = bogy_on (i);
        Result[i,3] = fairway_keep (i);
        Result[i,4] = (float)shot_miss (i);
        Result[i,5] = (float)approach_miss (i);
        Result[i,6] = (float)putt_sum (i);
        Result[i,7] = (float)out_sum (i);
        Result[i,8] = (float)in_sum (i);
        Result[i,9] = (float)score_sum (i);
        //もしiがkaisuuと等しくなったらループから抜ける
        if (i == kaisuu) break;
    }
    output_data(kaisuu)
}

上記が配列、For文、if文を使ったオーソドックスなプログラミングです。これは「手続き型」と呼ばれる方法で、そこに使われるのが多くの多次元配列とサブルーチン。実行文を見れば、どのような手順でプログラムが実行されるか分かります。

配列はエクセルと同様に、複数の情報を記憶するもの。サブルーチンは実行文が見易くなるように、細かい処理をサブルーチンに記載します。実行文からは引数やreturnを使って情報をやりとりします。

少し慣れれば、非常に見易いプログラミングなのです。一人で作る前提で、且つプログラミングを趣味にするならば、これで十分です。

太郎君はゴルフ仲間に「ゴルフスコア管理用プログラムを作ったよ」と話しました。

すると、「面白そうだから、ゴルフコンペ仲間の情報を全て入れて、色々な項目で年間表彰したいね。そのようなプログラムを作ってよ!」と言われ、太郎君はそれを引き受けました。

「ゴルフコンペの仲間は30人。その分配列を3次元にする必要がある。更に、今まではサブルーチンの結果をResultに格納するだけだったが、今後は仲間同士の結果を比較する新しいサブルーチンを作る必要がある。全てプログラミングを書き換えなければ・・・」

という感じになります。配列を多次元にするのは難しくありませんが、配列は全て数字でしか表現されていないので、どの配列に何を格納しているかが多次元になるとどんどん判り難くなってしまいます。

このような多次元の複雑なソフトを分かり易く表現できるようにするのが「パッケージで考える」プログラミング方法です。そこで使うのが構造体:structと、クラス:classとなります。

では上のプログラミングを、structとclassを使って書き直してみましょう。

//宣言文
//構造文:structを使い、MyStructというパッケージを作る
struct MyStruct
{
    public string basho;
    public string tenki;
    public string kaze;
    public string komento;
    public string hansei_bun;
    //コースのホール毎に情報があるものは2次元配列。18はホール数。
    public int [] par;
    //struct内の配列は宣言が必要
    public void Reset0() { par = new int[18]; }
    public int [] score;
    public void Reset1() { score = new int[18]; }
    public bool [] fairway;
    public void Reset2() { fairway = new bool[18]; }
    public int [] putt;
    public void Reset3() { putt = new int[18]; }
    public int [] bunker;
    public void Reset4() { bunker = new int[18]; }
    public int [] approach;
    public void Reset5() { approach = new int[18]; }
    public int [] shot;
    public void Reset6() { shot = new int[18]; }
    public float [] OB;
    public void Reset7() { OB = new float[18]; }
    // handicap~score_sumの結果10個をResultに格納
    public float [] Result;
    public void Reset8() { Result = new float[10]; }
}
//クラス:classを使い、類似のスコア計算用のサブルーチンをMyclassでひとまとめにする
class MyClass
{
    public void handicap(MyStruct han, int count)
    { han[count].Result[0] = 計算式; }
    public void par_on (MyStruct han, int count)
    { han[count].Result[1] = 計算式; }
    public void bogy_on (MyStruct han, int count)
    { han[count].Result[2] = 計算式; }
    public void fairway_keep (MyStruct han, int count)
    { han[count].Result[3] = 計算式; }
    public void shot_miss (MyStruct han, int count)
    { han[count].Result[4] = 計算式; }
    public void approach_miss (MyStruct han, int count)
    { han[count].Result[5] = 計算式; }
    public void putt_sum (MyStruct han, int count)
    { han[count].Result[6] = 計算式; }
    private void out_sum (MyStruct han, int count)
    { han[count].Result[7] = 計算式; }
    public void in_sum (MyStruct han, int count)
    { han[count].Result[8] = 計算式; }
    public void score_sum (MyStruct han, int count)
    { han[count].Result[9] = 計算式; }
    public void execute(MyStruct1 han, int count)
    {
        handicap(han, count);
        par_on(han, count);
        bogy_on (han, count);
        fairway_keep (han, count);
        shot_miss (han, count);
        approach_miss (han, count);
        putt_sum (han, count);
        out_sum (han, count);
        in_sum (han, count);
        score_sum (han, count);
    }
}
// 宣言したMyStructという構造体をgolfdataと命名し、1000回分の配列として確保
MyStruct[] golfdata = new MyStruct[1000];
//Myclassという宣言したクラスをgolfrsultと命名し、nullでgolfresultの割り当てを実施
Myclass golfresult = null;
//サブルーチン
//データ入力サブルーチンcountはコース回数。privateはここだけで使う宣言
private int input_data()
{
    //データ読み込み処理シーケンス記入。エクセルから入力予定?
    return count; //読み取れたコース回数
}
//データ入力サブルーチンint countはコース回数の引数
private void output_data(int count)
{
    //Resultの値を画面上に出力する処理シーケンス記入
}

//実行文
int kaisuu = input_data();
for (int i = 0; i< 1000; i++)
{
    golfresult.execute(golfdata, i);
    //もしiがkaisuuと等しくなったらループから抜ける
    if (i == kaisuu) break;
}
output_data(kaisuu);

如何でしょうか?宣言文は複雑ですが、実行文は構造文golfdataとクラス文golfresultだけしか使っていないのが分かるでしょうか?使っている配列は1次元だけです。

中身を読み出すのも分かり易いです。例えば100回目のコースの7番ホールのスコアを見たい時、最初の方法では

par[99, 6]で読み出せます。配列の最初が回数、次がホールを指していることを覚えておく必要があります。これが構造文ではgolfdata[99].par[6]の様に、配列の前に名前が付いており、管理がし易くなります。

サブルーチンも同様です。例えばアプローチミスの計算をする場合、最初の方法では、

approach_miss()のようにサブルーチンを使います。もし、複数人のアプローチミスの比較を行うサブルーチンを作るとき、approach_missという名前は使えません。

でもclass文を使うと、golfresult. approach_miss()の様な使い方です。複数人のアプローチミスの比較はhikakuという別のclass文を作れば、hikaku. approach_miss()のように全く同じ名前で別のプログラムを作っても問題ありません。

このように、同じ部類のメモリー領域をパッケージとして取り扱った構造文や、同じ部類のサブルーチンをパッケージ化したものを「オブジェクト」と言っています。

よって、これらを利用することが「オブジェクト指向」のプログラミングとなり、①の「抽象化 関連する属性とエンティティの相互作用をクラスとしてモデル化」という難しい言い回しは簡単に言うと「パッケージ化」です。

c#ではありませんが、複数のクラスをまとめたpackageというコマンドを使う言語もあります。

残りの③と④は殆ど趣味としてプログラミングをする時は使いません。簡単なプログラムでは「手続き型」の方が簡単です。配列やサブルーチンが複雑になってきたら、予め「オブジェクト指向」でプログラミングを検討した方が良いです。

趣味ですから、使い易い方を使えば良いと思います。色々な方法で読み易いプログラミングになるように考えるのも、プログラミングの面白さの一つで、バグを少なくし、継続率を上げる効果があります。

第7章 プログラミングの楽しさは「仕様と手順」から考える事


第5章の「Webから探し出す」は、プログラミングのノウハウを増やす事になります。第6章の「色々な方法で読み易いプログラミングになるように考える」は、デバッグ作業を簡単にして、プログラミング作業を継続し易くできます。

でも、最も楽しい作業が「考えて作り上げていく」と私は考えています。

上記の「仕様」とは一般的には物事をする方法。しかた。やりかた。機械類や建築物などの構造や内容と辞書に書かれています。

ソフトを作成する観点から考えると例えば、

「家計簿を管理するソフトを作ってほしい」という依頼が花子さんから太郎君にあったとします。太郎君はエクセルでキーボードから入力する「家計簿管理ソフト」を作成しました。

すると花子さんは、「違うよ。写真で取ったレシートを読み取って、その内容を分別し、家計簿に書き込んで管理してくれるソフトの事だよ!」と言いました。

このすれ違いはどちらが悪いと思いますか?どちらが悪いという訳ではなく、最初の時点で「仕様」が明確になっていなかったことが原因なのです。

花子さんは「写真で取ったレシートを読み取って、その内容を分別し、家計簿に書き込んで管理してくれるソフトを作ってほしい」と要求し、

太郎君は「c#を使い、OCR技術を利用するよ。但し、綺麗に印字されていないと上手く読めない可能性があるし、レシートのフォーマットが分からないと分別できないから、読み取るレシートを限定して教えてね」と返答すれば、行き違いは発生しませんでした。

これが最初に行う「仕様を決める」という行為です。これは自作するプログラミングでは、Webでどんな技術開示があるか検索し、それを自分で使える環境にあるか確認する作業です。

Geasyoneではそれをどのような経緯で進めたか確認してみましょう。

下の例はGeasyoneを使い、麻雀牌を3D画像として出力したものです。でも、Windows10の3dビューアー等の3D出力専用ソフトを使えば、簡単にこのような画像を出力できます。

麻雀牌の3D表示


単純に3D画像を出力してみるだけならば「画像を鑑賞する」という趣味です。プロのピアニストの曲を聴く「音楽を鑑賞する」という趣味と同じです。

音楽を鑑賞し、「すごいな~自分もピアノを弾けるようになりたい」という気持ちが「ピアノを習い、弾けるように練習する」というモチベーションにつながり、それが趣味となります。

それと同様に3D画像を見て、「すごい技術だな~自分もこんな表示できるソフトが作れるようになりたい」という気持ちが、「プログラミングを習い、使えるように慣れる」というモチベーションにつながり、それが趣味となります。

c#を使えば、3D画像の表示を行う事は可能です。Webで調べれば、OpenGL,OpenCV, DirectX,SurfaceAnalyzer, VTK等の3Dデータの入力、表示等を行うライブラリーを使用する方法が紹介されています。

でも、これは第5章の「Webから探し出す」こと。Geasyoneの表示は、その先に一歩足を踏み入れて、麻雀牌の3D画像の読み込みから出力まで、全て上記ライブラリーを使わない手作りです。

「ライブラリーが揃っているのだから使えば良いのでは?何故そのような無駄な事をするの?」と疑問を持つ人がいるかもしれません。

理由は簡単です。「自分で考えて作れることが多くあるから」です。

例えばDIY(Do It Yourself)で本棚を作ることを考えてみましょう。

ショップに行って、本棚を作るキットを見つけ、自宅で組み立てるのもDIYです。簡単に言うと、プログラミングではこれが3D表示用ライブラリーを活用するということに相当します。

しかし、自分で本棚を作るための木の板を購入し、ノコギリや釘、塗料を使ってオリジナルの本棚を作り上げるのもDIYです。後者の方が考えなければならないことが多いですよね。

これがまさに3Dライブラリーを使わず、「手作りで3D画像表示ソフトを作る」ことに相当する「プログラミングのDIY」と考えました。

本棚作りで考えると、作り上げるまでに木の板から部品を切り出し、釘とトンカチで部品を組み立て、ニスで塗装するという手順が必要です。一つ一つの内容はシンプルなので、作業を行い易いですよね。

プログラミングも同じです。内容が簡単でシンプルならば、人は容易に作業(考えること)を始めることができます。

これで「仕様」が決まりました。仕様は「3Dライブラリーを使わず、手作りで3D画像表示ソフトを作る」となります。

3Dライブラリーを使わないということは、3Dで画像を表示する手順が公開されており、その手順でプログラミングを行っていけるかを確認する必要があります。

では上記3D画像の表示を簡単な技術要因に分けられるか調べていきましょう。

麻雀牌は3Dデータですが、表示は2次元の画面上で行われています。これは「レンダリング」という技術が使われています。

レンダリングされた麻雀牌の画像は矩形形状ですが、上面が黒っぽく、正面が明るく見えています。これは一方向から照明を当て、牌の表面で照明光が拡散して反射し、その反射光をカメラで見ているためです。

仮想的な麻雀牌に光を当てた時の反射光の強弱により、同じ白色に明暗の色の差が発生しているのです。もし、照明や拡散の計算を行わなければ、矢印のように同じ白色で表示されます。

照明on/offの比較


では仮想的麻雀牌はどのように作られているのでしょう?3Dモデルとは、その表面をポリゴンという3角形で形成した集合体です。大きい平面は大きなポリゴン、曲面や小さい平面は小さなポリゴンの集まりで作ります。

その各ポリゴンの頂点は、テクスチャーという画像と対応付けられており、テクスチャーをポリゴンに貼ることで、3D画像として表現できています。もしテクスチャーを貼り付けなければ、ポリゴンの集合体のみで3D画像を表すことができます。

3D画像のポリゴン化


次に、そのポリゴンの集合体から一つのポリゴンを取り出してみます。ポリゴンは3次元の空間内の3つの点(X1,Y1,Z1)、(X2,Y2,Z2)、(X3,Y3,Z3)で表せます。

この3点がXY平面上に全て来るようにポリゴンを回転させると、ポリゴンは(x1,y1,0)、(x2,y2,0)、(x3,y3,0)の3点で表せます。zは全て0なので、この3角形は2次元座標の3点(x1,y1)、(x2,y2)、(x3,y3)となります。

ここでテクスチャーと呼ばれるポリゴンに貼り付けるための画像は、2次元画像です。

3D画像のポリゴンとテクスチャー


ポリゴンの頂点(x1,y1)、(x2,y2)、(x3,y3)にそれぞれ対応するテクスチャーの位置(tx1,ty1)、(tx2,ty2)、(tx3,ty3)が決まっていればポリゴンにテクスチャーを貼り付けることができます。

これを逆に考えて行けば、ポリゴンデータとテクスチャーデータから3Dモデルを作成する「手順」となります。

「3Dモデルはポリゴンの集合体で作り、そのポリゴンは3頂点の座標とその頂点に対応するテクスチャーの2次元画像で管理します。」という共通のルールに基づき、3Dデータファイルや3D画像表示ソフトが作られます。

このように一見複雑な3D画像は、仕様とその手順が明確なのがわかります。2次元の画像処理技術に3次元の座標変換、平面に対する光の反射と拡散という数学及び、物理の計算で表現できるように手順が決められているのです。

仕様に対しその手順がしっかり決まっており、その内容が公開されていれば、他人が作ったライブラリーを使わなくても、自分で作れるはずです。

「プログラミングを趣味にするために、数学や物理を細かく勉強するのは・・・」と思い方も多いと思います。実は私も数式を覚えるのが大の苦手で、細かい勉強などはしていません。

もしそこの数学や物理が楽しいと考える人は、中学校や高校、大学の教科書を持ち出して勉強し直せば良いと思います。私はその概念だけ理解して、計算式などは全てWebのコピペで済ましています。

計算式のコピペをしても、ポリゴンとテクスチャーの対応付け等はプログラミングとしてその計算式を盛り込み、決まった手順通りに上手く動作させる必要があります。

例えば、3DデータにOBJファイルというものがあります。まず、そのOBJファイルからポリゴンの頂点とそれに対応したテクスチャーが何処にあるか、どのように関連付けられているか調べ、それを読み出してプログラムの中に格納する必要があります。

格納したそれぞれのデータに対し、Web調べた座標変換行列をどのように関連付けて使用するか、画像表示技術のどれを使って上手く表示するか等は、全て自分で考えプログラミングしていく必要があります。

数学や物理ができる・できないと、プログラミングができる・できないは全く別物です。

ポリゴンとテクスチャーを関連付けた表示→3次元座標変換で上手くポリゴンとテクスチャーが連動して動くか→ポリゴンを集合体として上手く表示できるか→照明と拡散データに基づき上手く3Dが表示できるか・・・

一つ一つのプログラミングで、上手く出力できると大きな達成感を感じることができます。この辺はライブラリーを利用してしまうと感じられない楽しさです。

一見複雑そうなことでも、一つ一つは簡単な技術であり、それらを積み重ねることで、難しそうな技術が実現できます。プログラミングの過程にはそう言った面白さがあるのです。

第8章 プログラミングの楽しさは「無いもの」を考える事


第7章では「仕様と手順」が分かっている技術を、プログラミングを通して作り上げていく楽しさを紹介しました。でも、仕様と手順が分かっていないと楽しめないのでしょうか?

実はそのようなことはありません。3D画像の表示については仕様と手順がはっきりしていますが、2次元の画像処理の方法については明確な仕様や手順は殆ど公開されていません。

例えば画像処理のスポット修正。各画像処理ソフトを使って修正するテクニック等はWebで見つけ出せますが、その処理自体の具体的な中身とかアルゴリズムが公開されてはいません。

理由は、「これだ!」と言った明確な共通手順が無く、各社でその手順が決められているからです。仕様は「消したい画像を削除し、違和感の無い画像に置き換える」となります。

元々は「消したい画像」があった部分ですので、そこに置き換わる画像は創造物です。実際にその場所には存在していません。その写真に違和感がなければ、手順は何でも良いのです。

各画像処理ソフト開発メーカが、違和感の無いスポット修正のアルゴリズム開発にしのぎを削っているのです。そのような環境で、自分でもそのアリゴリズム開発をすることにワクワクしてしまいます。

あくまでも趣味ですので、ソフト開発会社より優れているものを作る必要はありません。それに近づけるスポット修正のアルゴリズムが独自に開発できれば良いのです。

題材はWeb上に「スポット修正」で検索するとたくさんあります。例えば、


で検索した題材に対し、周辺の情報から消した部分を連結するGeasyoneの「連結」というアルゴリズムで、スポット修正に近い結果となっています。

スポット修正1


ではもう少し複雑な修正例を4つ。


で検索した題材に対し、画像全体から消した部分の模様に近い画像を自動選択する「穴埋め」というアルゴリズムで、3回に分けて柱を消して「穴埋め」したところ、違和感の無いスポット修正ができました。

スポット修正2


次にもう少し創造に限定がある例として、


で検索した別の種類の画像題材に対し、「穴埋め」を実施しました。同様に修正できている感じがします。

ソフトウェア画像取り込み


最後に画像修正王者のPhotoshopを使った画像修正3例で確認。


で検索した画像題材に対し、「穴埋め」を実施しました。消去範囲が小さく、置き換える画像も豊富にあるので問題なく修正できました

ソフトウェア2次元画像処理


次の画像題材でも「穴埋め」を実施しました。やはり消去する物体が大きくなると違和感なく消去するのは難しくなります・・・でも、消去→穴埋めを数回繰り返すと良い感じでスポット修正できました

アルゴリズムを考えて行くにはやりがいのある課題です。

プログラム2


最後は面白そうな題材。一発で穴埋めができました。消去部分は大きくても、その代替えとできる画像部分が多ければ、一発で修正できる場合もあります。実際に試すときは上手く行くかワクワクします。面白いものです。

プログラム3


リンク先の方々には題材をお借りしました。ありがとうございます。

これらのアルゴリズムは公開されていません。更に、各メーカのスポット修正の結果が「正解」という訳でもなく、あくまでも修正した部分が分からず、自然な写真に見えることが重要です。

このような未知の世界のアルゴリズムを考えて行くのもプログラミングならではの醍醐味です。

如何でしょうか?世の中には色々な技術があり、その内容が未公開のものがたくさんあります。何かの技術に目を付けて、それを自分の手でプログラミングを使って開発してみる。

結構、やりがいのある、楽しく面白い趣味になると思いませんか?