質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

Q&A

解決済

1回答

1559閲覧

コンソールアプリでの諧調表現

fana

総合スコア11996

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

0グッド

0クリップ

投稿2021/08/04 05:52

編集2021/08/04 06:06

技術的な問題ではない感じで恐縮ですが……


質問内容

Win32コンソールアプリケーションで printf で表示を行っているのですが,どうにかして明るさの諧調を表現したいです.

例えば,黒字に白で文字が表示される場合,+ よりも # のほうがより白が多いために明るく見えると思うので,これを利用すれば明暗2諧調を表現できます.
そういった感じで,いくつかの種類の文字を用いることによって数段階の諧調を表現したいです.
このことに適した文字のセットとして何か良いものが無いでしょうか?

  • 半角の方がうれしいですが,そうでなくとも構いません.
  • 諧調数は最低でも5段階くらいは欲しいです.

3段階とかであれば,.oO とかで行けるかな?と思うのですが…


背景事情

文字でピラミッドを表示するプログラムを作っています.
以下のような表示を行うものです.これは3段のピラミッドです.

| | | | | #### | | #### | | ######## | | ######## | | ############ | | ############ | | | | |

解像度と見る角度を変えると,以下のようになります.
全てを # で描画すると何が何だかわからなくなってしまうので,この例では,各面をそれぞれ固定の文字で表示しています.

| | | | | ^^^^^^^^^^^^^ | | +^^^^^^^^^^^^### | | +++++++++++##### | | +++++++++++##### | | +++++++++++##### | | ^^^+++++++++++#####^^^^^^^# | | ^^^^^^+++++++++++###^^^^^^^### | | ++^^^^^^^^^^^^^^+++^^^^^^^###### | | ++++++++++++++^^^^^^^^^######### | | ++++++++++++++++++++++########## | | ++++++++++++++++++++++##########^^^^^^^# | | ^^^++++++++++++++++++++++########^^^^^^#### | | ^^^^^^++++++++++++++++++++++#####^^^^^^####### | | +++^^^^^^^^^^^^^^+++++++++++++##^^^^^^^######### | | +++++++++++++++^^^^^^^^^^^^^^+^^^^^^############ | | +++++++++++++++++++++++++++^^^^^^^############## | | +++++++++++++++++++++++++++++++++############ | | +++++++++++++++++++++++++++++++++######### | | +++++++++++++++++++++++++++++++++####### | | ++++++++++++++++++++++#### | | +++++++++++## | | | | |

今やりたいことは,シェーディング計算の結果を表示に反映させることです.
シェーディング計算の処理と,表示すべき明るさを数段階に離散化した結果を得るところまではできています.
↓はその結果を数字で表示している(数値が大きいほど明るい)例ですが,これでは見た目として意味がわかりません.
コンソールアプリにおいて明るさを適切に表示する方法について,前述のように困っている状況です.

| | | | | 1222222222222 | | 11222222222222 | | 11777777777777 | | 11777777777777 | | 2222211777777777777222 | | 1222222117777777777772222 | | 11222222177777777777722222 | | 111222222772222222222222222 | | 11112222222222777777777777772 | | 1222222111177777777777777777777777722 | | 11222222111777777777777777777777777222 | | 111222222117777777777777777777777772222 | | 1111222222177777777777777777777777722222 | | 11111222222777777777777777777777722222222 | | 11111222222222222222222222222222222777777 | | 1111177777777777777777777777777777777777 | | 1111177777777777777777777777777777777777 | | 111177777777777777777777777777777777777 | | 11177777777777777777777777777777777777 | | 1177777777777777777777777777777777777 | | 17777777777 | | | | |

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/08/04 06:11 編集

普通に画像生成して、アスキーアート生成する系のライブラリに食わせるのではダメですか? それとも、自分でそういうライブラリを作りたいという話?
fana

2021/08/04 06:25 編集

そういったライブラリがどのようなOUTをくれるのかがわからないので,結果の可否についてはお答えできませんが… 方法論としては可能な限り何らかのライブラリを追加導入するようなことはしたくないと考えています. (Visual Studioでプロジェクト作って,ソースコードを突っ込んだら即動く,が理想)
fana

2021/08/04 06:39

> それとも、自分でそういうライブラリを作りたいという話? そのような大それた話ではありません. 用途としてはいわば,「3DCGの勉強用」みたいなものです. * 可能な限り演算内容や実装を何らかのライブラリの裏に隠したくありません. * 使われているライブラリの導入とか使い方を知る必要が…とかいう余計な話があるのはうれしくありません.  コンソールでprintfなのは,最も面倒がないと考えるからです. * 結果が一発出て終わりならばPGMとかで画像出力して別途見る,とかでもまぁいいかなと思うのですが,動的に座標変換具合やら何やらをキー入力で変えて見るとかをするにはそういった形態は面倒だと思っています.(個人的にいちいちファイルが出るのも嫌)
退会済みユーザー

退会済みユーザー

2021/08/04 06:49 編集

Win32なら、普通にGDIでウィンドウに描画すればいいかなという気がしますが… CGの勉強という事であれば画像をそのまま表示して視認した方が間違い無いと思いますが、敢えて文字に変換する必要性がよく判りません。
fana

2021/08/04 06:57 編集

教材の一部としてのコードを作る状況において,その形態を模索している,という感じです. この質問に対して十分に良いと思える回答がもらえたとすれば,最もシンプルな(…と私が今現在個人的に考えている)形態をとり得る,ということです. GDIを用いれば,相手次第ではGDIの部分が丸ごと「?」な要素になるでしょう. printfやscanfの世界で物事が収まるならば,そのようにしたいと考えています. 「C++の入門書は読みました」くらいの相手でもいじくって試せるコードを用意したい,という感じです.
fana

2021/08/04 07:03

この私の考えていること自体が良いとかか悪いとかいう話については様々ご意見あるでしょうが,それは単なる背景事情なのであって,この質問の内容が変わるわけではありません. やろうとしていることの代替手段が欲しいわけではないのです. 質問内容は明確であると思っています.
dodox86

2021/08/04 07:18

> このことに適した文字のセットとして何か良いものが無いでしょうか? ということであれば、フォントの見た目の問題も切り離せない気がするので、いっそフォントとしてそれ用のものを作るとか。(で、インストールしてターミナルのフォントに使用するなど)それも代替手段に含まれてしまうでしょうかね。
退会済みユーザー

退会済みユーザー

2021/08/04 07:19

フォントのグリフ取得して輝度の平均計算とかして変換テーブル作るみたいなのを考えたけど、普通に画像で出力するより面倒そう。あとフォント変わったら見え方変わるけど、そのへん許容できるかとか。
fana

2021/08/04 07:22

(私はそんなに面倒なことを言っていますか?)
退会済みユーザー

退会済みユーザー

2021/08/04 07:23

はい。
fana

2021/08/04 07:31 編集

そうですか…… 私はそこらへんに疎いのですが, 例えばWin10で標準的に入っている(わざわざインストールとかしなくて良い?)何らかのフォントがあるとして, 「そのフォントを使う場合においては」というような話でも構いません. (その場合,できればそれらの文字の見た目を画像か何かで提示して頂けると助かる)
退会済みユーザー

退会済みユーザー

2021/08/04 07:38 編集

結局、出力された結果がいい感じに見えるかどうかは主観が入るので、実際に自分が試していい感じに見える変換テーブル作って出力するしかない気はします。(手作りするか、フォントから何らかの計算で生成するかは置いといて)
fana

2021/08/04 09:03

(限定条件下で簡単に検討してみた事柄を回答として記しました.)
guest

回答1

0

自己解決

質問への追記・修正の依頼

にて頂いたご意見を参考に,少しばかり検討してみました.

とりあえず
「私の環境でコンソールアプリを動かしたときの表示結果において」
どの文字がどのくらい白画素持っているのか?
というのを,半角な文字群(文字コード 0x20 ~ 0x7E)の範囲に関して調べてみました.

(1)文字群の絵を得る

↓のコードで文字群をコンソールに表示し,その結果を PrintScreen して絵を取得.

C++

1int n=0; 2for( char c=0x20; c<=0x7E; ++c ) 3{ 4 putchar( c ); 5 ++n; 6 if( n==16 ){ putchar('\n'); n=0; } 7} 8putchar( '\n' );

(2)文字群の白画素個数を数える

(1)で得た画像を,以下のコードに食わせて,
各文字領域内の白画素数をカウントし,当該カウント数でソートした結果を表示して見た.(カウントにはOpenCVの countNonZero を使用)

C++

1int main() 2{ 3 cv::Mat Img = cv::imread( "Chars.png", cv::IMREAD_GRAYSCALE ); 4 if( Img.empty() )return 0; 5 cv::threshold( Img, Img, 127, 255, cv::THRESH_BINARY ); 6 cv::Mat Test = cv::Mat::zeros( Img.size(), CV_8UC3 ); 7 const int GridW = 10; 8 const int GridH = 20; 9 10 std::vector< std::pair<int,char> > Data; 11 Data.reserve( 0x7F - 0x20 ); 12 13 { 14 char C = 0x20; 15 for( int y=0; y<6; ++y ) 16 { 17 for( int x=0; x<16; ++x, ++C ) 18 { 19 cv::Rect Range( x*GridW, y*GridH, GridW, GridH ); 20 cv::Scalar color = ( (x+y)&0x01 ? cv::Scalar(0,0,255) : cv::Scalar(0,128,0) ); 21 cv::rectangle( Test, Range, color, -1 ); 22 23 int n = cv::countNonZero( Img(Range) ); 24 Data.emplace_back( n, C ); 25 } 26 } 27 } 28 Test.setTo( cv::Scalar(255,255,255), Img ); 29 cv::imshow( "Test", Test ); 30 31 std::sort( Data.begin(), Data.end() ); 32 int nPrev = -1; 33 for( int i=0; i<Data.size(); ++i ) 34 { 35 int n = Data[i].first; 36 if( n != nPrev ) 37 { 38 std::cout << std::endl << n << " : "; 39 nPrev = n; 40 } 41 std::cout << Data[i].second; 42 } 43 std::cout << std::endl; 44 cv::waitKey(); 45 return 0; 46}

↑のコードで作ってる画像Testは,各処理領域範囲を描画してみたもので,こんな感じになってる.
各矩形範囲に文字が1個ずつちゃんと入っていることがわかる.
イメージ説明

処理結果,以下の出力を得た.
先頭の値が白画素のカウント数であり,コロンを挟んで右側にはそのカウント数になった文字を列挙している.
(ほんとは最初の行にカウント0の表示も出てくるけどそれは不要なのでここでは省略)

3 : ` 4 : . 5 : ^ 6 : ', 7 : - 8 : ": 9 : ~ 10 : ;_ 12 : i 13 : <> 14 : !=r 15 : +l 16 : j 17 : 1 18 : ()/vx 19 : I 20 : c| 21 : Jty 22 : 7?Lf 23 : TY 24 : nouz{} 26 : []k 27 : V 28 : FZes 29 : 2CXahpq 30 : 34 31 : *Sw 32 : AKPU 33 : bd 34 : &0\m 35 : 5EG 36 : 8HOg 37 : 69 38 : DR 39 : Q 42 : #$BN 44 : % 45 : W 53 : M 54 : @

(3)グラデーションになるか見てみる

この結果を踏まえて,
白画素数3個~54個までの間を適当に10種類選んでコンソールに並べて出力してみたところ,下図のようになった.
理屈の上では(それなりにモニタから離れて見れば)これがグラデーションに見えるハズである.

イメージ説明

実際に見てみて,よいディザリング結果と思えるか? というと,特に右半分がイマイチな気がする…


↑で選び出した文字を,質問文記載の明るさデータに与えてみた.
モニタからある程度距離を取って見れば,まぁ無くもない感じか…?
(※このピラミッドなモデルだと一度に見える面の向きが多くても3種類でしかも互いに向きは直交しているから,見た目の評価を行うにはかなり有利な条件ではある)

イメージ説明

投稿2021/08/04 08:55

編集2021/08/04 09:43
fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/08/04 09:01

やってみると, ` と " の間に結構な差が見える とか 小文字の b や d が割とカウント数上位にある とか # が最強と思ってたけども白画素個数的にはより多いやつがいる とか 割と発見があった.
fana

2021/08/04 09:09

各文字をディザマトリクスと見なして考えれば, 白画素がなるべく一様に分布しているような文字を選ぶと良いのかな…?
退会済みユーザー

退会済みユーザー

2021/08/04 09:16 編集

元画像の部分ピクセルとフォントとの近似画像検索とかするとよりそれっぽくなるかもしれない…
退会済みユーザー

退会済みユーザー

2021/08/04 09:47

こうして画像見ると、意外と悪くないっすね。簡易実装としては十分アリかと。
fana

2021/08/04 09:49 編集

> 元画像の部分ピクセルとフォントとの近似画像検索 コンソールの世界での解像度(縦横の文字の個数)よりも高解像度な「元画像」があって,それを文字で表すならば,そういう方向もありそうですね. ※そういう意味では,今やってるのは両者の解像度が一致している状態,と言えるのかな.
fana

2021/08/04 09:53

明るさを面の法線だけから計算していることもあり,回転させてると唐突に全部同じ文字になっちゃったりしてビビる
otn

2021/08/04 13:43

懐かしいですね。 1960-70年代、コンピューター用プリンターがインパクト式のラインプリンターしか無かった頃に、 絵を印刷するのにそういう手法が使われていました。当時のデータはおそらく手作り。 ちょっとググってみたけど、インターネット普及以前の時代のことなので、余り情報は無いです。かろうじて、https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13242823813 くらいですが。役立つ情報では無い。
yominet

2021/08/04 14:59

「変換用の文字列を作成しておきたい」ということであればですが… 既存のアスキーアート変換ソフトやサイトで グレスケールのグラデーションした画像を変換しておき、 その結果の文字列を変換用テーブルとしてもっておくのはいかがでしょうか?
fana

2021/08/06 01:21

「アスキーアート」というと,個人的に某所のプロポーショナルフォントな環境でのものを思い浮かべてしまいますが, 等幅フォントでやれるやつがあるなら使えるかもしれませんね.
fana

2021/08/06 01:29

1日ほど様子を見ましたが,回答が付きませんでしたので,自己解決の形をとらせていただくこととします. そのものズバリな形での回答こそ得られませんでしたが, コメントを頂く中でやるべきことの方針が明確化され,助かりました.
fana

2021/08/06 01:43

まとめ: 何かしらの「よく使われる」パターンみたいなのがあったりしないのだろうか?とか思ったりしたが,そのような回答は無かった. 結局定性的な評価になる話なので「コレ」というものが確立されていないのかもしれない. 今後の課題: * 画素の分布を考慮した文字選択基準の検討  (一様に分布している方がよいのでは? とか,隣接諧調間で文字形状が似ている方がよいのでは? とか) * 複数種の文字をもちいたタイリング等の検討  (白画素の個数が同じ文字を交互に並べて見るとか,あるいは文字種を絞ってタイリングで中間諧調を表現した方が複数種の文字を用いる場合よりも見た目がごちゃごちゃしなくてよい的な方向の可能性とか)
退会済みユーザー

退会済みユーザー

2021/08/06 02:05 編集

エスケープシーケンス等で色を変える事で更に段階的な輝度の調整みたいな事は出来るかも。 (Bは暗い、Gは明るい等の差があるので) 色が混ざるとごちゃごちゃして見づらくなる懸念はありますが。
fana

2021/08/06 02:11

Windowsのコンソールでエスケープシーケンスで色を変えるのは無理(? あるいは,できるようにするために手間がかかる?)なのかなぁ. #コンソール用のAPIとかに手を出し始めるとそれこそ「これもうGUIにした方が話が早いんじゃないかな」ってなりますし.
fana

2021/08/06 02:16

(C言語の課題か何かで「文字でピラミッドを表示」みたいな話をたまに見かける気がしますが,実際やってみると結構面倒ですね.)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問