mikeo_410


1.私の視覚

私は何を見ているのでしょう。明るさ、輝き、色、形でしょうか。
目の働きは、と考えると、物にぶつからないように、あるは字を読むといった形の知覚が浮かびます。
形状の認識には、距離、大きさ、硬さ(質感)が思い付きます。
目の機能は、と考えると、光を捉える(受光素子)機能だと思います。
明るさ、輝き、色を捉えて、形を認識しているようです。
強いて分ければ、実用的には形を、心理的には美しさ(山紫水明、朝日が心地良い、...)が、私の視覚のようです。

2.視覚の記憶

私は色を記憶できないように思います。記憶しているのは、形状と心象です。
カラー写真のような絵を書く人がいるわけですから、色の記憶が出来る人もいるのだと思いますが、私には心象としてしか色の記憶が残りません。
郵便ポストだから赤いとか、目が覚めるような景色だったのでこんな色名はずだとかで記憶しているようです。

3.色

形を認識するために明るさの差を捉えているので、赤い車もべったり同じ色に見えているわけではありません。
「色」と言ったときには、赤い車の「赤」だったり、赤い車の部分を描くときに選ぶ絵具の「色」だったりします。
前者は、色相と呼ばれるようです。光の周波数に相当しているのだと思います。
もう一つ、物理的に計測可能なのが強さ(エネルギーの大きさ)で、これが明るさ、輝き、彩度と表現されるものの源だと思います。
目を、光を捉える受光素子だ、と考え、捉えることが出来るのは、周波数ごとの強さだと考えることにします。
「色」は、「周波数ごとの強さの組」を表し、周波数は「色相」と呼ぶことにします。
「色」は、目が知覚可能な情報の全ての組を表すと考えます。
(本当は、気温や触覚、心理状態も色の認識に関係がる、あるは色の記憶に関係があると思うのですが、本題から離れるので置いておきます。
また、時間と言う要素も置いておきます。)

4.デジタルカメラの視覚

CCDがデジタルカメラの受光素子に使われていることは知っていますが、色はどうなっているのでしょう。
CCDは光の強さを電気信号に変換するものと思います。周波数(色相)はフィルタによっているようです。
イメージとしては、4つの物理画素(受光単位)にR、G、B用のフィルタを付け(Gは2つ)、この出力を論理的な1画素としていると言うことで理解しています。
実際のデジタルカメラやケイタイはコンピューターであり、画像処理専用の素子もあり、単純ではなく、究極的な単純化が施されていると思います。

データを処理する観点で考えると出来るだけ素なデータが良いように思います。しかし、デジタルカメラも目標は、視覚に近づけること、
(あるいは綺麗に見せること)でしょうから、補正をしてくれていると考えます。

5.色の数値表現

デジタルカメラのことを考えると、フィルタで分光される3つの周波数領域の強さしかないので、RGBで色を表すことは必然です。
自然の環境では連続的な周波数であるのに、3領域にすることの影響はわかりません。ただ、人間の知覚に近づけようとデジタルカメラが作られており、
人の目も連続的な周波数の変化を細かく捉えていないことも確かだと思います。
むしろ、デジタルカメラは、明暗による色相の認識の変化と言ったことのノーハウを持っており、補正しているのだと期待しています。

6.色の認識と数値表現

色の認識を考えると、周囲の色や方向で同じものがいろいろに見えることから、数値化した値と1対1の関係にないことは確かです。

7.色の数値表現の種類

RGB以外に、HSBなど複数の表現方法があることは気が付いていました。しかし、測定されているのが、RGBの3領域の強さであることからRGBだけを使っていました。
色を作る観点では、RGBは直感的ではありません。色相を角度で表すHSBなどの方が数値が表す色を予測しやすいと言うことです。
もう一つありえる観点は、認識の観点からの表現です。同じに見えるものは、同じ領域にあるような表現です。
R言語で、ナンクロのマス番号認識のしたいと考え、R言語のビットマップの扱いを調べていて、CIE L*a*b*という方式があるのを知りました。
これをcolorspaceパッケージを使って試してみます。

下図は、雑誌のナンクロの問題を撮影したものです。

下隅

中央


フラッシュの影響で、グレースケール化、2値化をすると、4隅では、白が黒になってしまいます。

RGBのそれぞれの平均値は、(140,138,141)と(181,172,166)で、グレースケール化した値の平均は、141と169です。
閾値の問題と捉えることも出来ますが、もっと視覚に近い方法がありそうに思います。

adbeのサイトには、1976 CIE u',v'色度図がありました。L*a*b*は図がないのでl*u*v*を見てみます。

 

色度図ではu'が0から0.7,v'が0から0.6の空間に、(0,06),(0.25,0),(0.62,0.52)を頂点とする三角形に近い形をしています。
colorspaceパッケージのLUVのU,Vは、1976 CIE u',v'色度図の目盛りとはあっていません。

下図は、colorspaceパッケージのLUVでL,U,Vの[0,100]、[-100,100]、[-100,100]の色を作り、RGBに変換して、C#で描画したものです。1pixelに色をを設定し、ストレッチで拡大表示しています。


どうも、白である(2.1,4.2)あたりが中心になるようにして、白の近くを扱うのがcolorspaceパッケージのLUVのようです。

 

 

 

L*a*b*も感じを掴むために図示してみます。下図は、L*が 25、39、53、67、81、95 の6枚です。各図とも、-100から100を50分割し、a,bの値とし、(b,a)の位置にLAB()の返す値をプロットしました。他の方向から見た図が、「colorspaceパッケージのLab」にあります。

   
     

8.R言語の色の表現

R言語で色を使うのは、plot()などの col= のオプションです。
整数値を書くと、パレットのインデクスとしてパレットの設定色が使われます。
> palette()
[1] "black"   "red"     "green3"  "blue"    "cyan"    "magenta" "yellow" 
[8] "gray" 
> palette(c("red","cyan","blue"))
> palette()
[1] "red"  "cyan" "blue"
> palette("default")
> palette()
[1] "black"   "red"     "green3"  "blue"    "cyan"    "magenta" "yellow" 
[8] "gray"   
>

col="red" のように、色名でも指定できます。
> colors()
  [1] "white"                "aliceblue"            "antiquewhite"        
  [4] "antiquewhite1"        "antiquewhite2"        "antiquewhite3"       
   :
[655] "yellow3"              "yellow4"              "yellowgreen"         
>

col=には、rgb(),hsv(),hcl(),gray(),rainbow(),heat.colors(),topo.colors(),terrain.colors()を記述でき、
いずれも、文字列か、文字列のベクトルを返します。
> r<-rgb(1,0,0,1)
> g<-rgb(0,1,0,1)
> b<-rgb(0,0,1,1)
> r
[1] "#FF0000FF"
> g
[1] "#00FF00FF"
> b
[1] "#0000FFFF"
>
(R,G,Bの範囲は、maxColorValue で決まり、デフォルトは1。)
#と8桁の16進数の文字列を返し、RRGGBBAAを表します。#と6桁の16進数の文字列も可のようで、この場合はRRGGBBです。

9.ビットマップ表示するには

 

どうもドット単位にカラーを指定して描画する直接的な方法はないようです。
image()が近いもののようです。
image(x,y,z,col=colors)
colors[]には、使用する色を並べます。z[x,y]は、colorsのインデクスになっています。

> colors<-rainbow(9)
> colors
[1] "#FF0000FF" "#FFAA00FF" "#AAFF00FF" "#00FF00FF" "#00FFAAFF" "#00AAFFFF"
[7] "#0000FFFF" "#AA00FFFF" "#FF00AAFF"
> z<-matrix(1:9,nrow=3)
> z
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> image(1:3,1:3,z,col=colors)
>

 

 

 

 

ビットマップを読み込むエクステンションを書いて読み込んでみました。
これで、いろいろ試して見ることができそうです。

# Bitmapの読み込み
bm_read <- function(path)
{
    bm <- .Call("Read", path)
    return(bm)
}
# Bitmapの表示
bm_image <- function(bm)
{
    # bmの内容をRの#で始まる16進文字列に。順序は、そのまま。x(水平)方向にスキャン。
    rgb_c <- rgb(bm$rgb[1,],bm$rgb[2,],bm$rgb[3,],maxColorValue=255)
    cols <- unique(rgb_c) #通常、色は重複するので一意に
    # zにcolsへのインデクスをセット。rgb_cは一次元。幅で切って2次元に。z[x,y]。
    # rgb_cは、TOP->BOTTOMだが、imageは、逆。
    z <-  matrix(match(rgb_c, cols), nrow=bm$width)
    image(0:bm$width,0:bm$height, z[,bm$height:1], col=cols)
}

これを使って、

> img <- bm_read("DSCF0670.JPG")
> bm_image(img)
>

10.グレースケール

 

前の例の img を、以下のようにして、グレースケールで表示してみた。 

> y <- (img$rgb * c(306,601,116))
> gray <- (y[1,] + y[2,] + y[3,]) / 1024
> rgb_c <- rgb(gray,gray,gray,maxColorValue=255)
> cols <- unique(rgb_c)
> z <-  matrix(match(rgb_c, cols), nrow=640)
> image(0:640,0:480, z[,480:1], col=cols, axes=F, xlab="", ylab="")
>

表示装置(モニタ)はウインドウごとに異なる条件で表示しているわけではなく、一律の解像度、色数で表示しているのですから、グレースケールもカラー表示だと言うことにやっと気が付きました。カラー画像をグレースケール化するときに、各色に乗じる定数は決まっているようです。
逆はどうするのでしょう。同じ値を設定して一見よさそうですが。
考え付く基準は、ツブレやトビがないこと、階調が多いことです。

 

 

 

 

 

11.RGBで色の分布を見る

 

左図は、雑誌のナンクロをデジタルカメラで撮影したものの一部で、全体は780x767ドットです。
この度数分布を図にしてみました。
598,260ドットで、22,918色(RGBの組)が使われています。
すべてをプロットすると、すべて同じ色になってしまったので、100,200超と度数の小さいものを捨てて描画してみました。
200超で、52%のドットが含まれます。
作図に使ったR言語のスクリプトは、「R言語」「サンプル」にあります。

度数に対応した色は、rainbow(使われている色数)で作りました。

 

 

 

 

 

 

 

 

12.colorspaceパッケージのRGB

ここでは、2値化するのに色の要素が使えないのかと言うことを考えています。colorspaceパッケージをデフォルトで使って出来ることで十分と思っていましたが少し深入りしてしまいました。

RGB(R/255,G/255,B/255)
は、使い方が間違っていました。

パソコンで普通のRGBは、他のRGBと区別が必要な場合はsRGBと表記されているようです。
ガンマ補正されたRGBと解釈すればよさそうです。これに対して、ガンマ補正していないRGBをリニアRGBと呼んでいます。
colorspaceパッケージのRGB()の引数は、リニアRGBでした。
パソコンのRGBが入力にならないのでは、始まりません。もう一つの入り口、16進文字列からのRGB生成、hex2RGB()を試します。
こちらは、sRGB->リニアRGBが働いてOKだと分かりました。

通常、sRGB->リニアRGBには、指数に2.4が使われるようですが、colorspaceパッケージのRGBは、2.2が使われていることもわかりました。

 

> # R の基本の色の扱い -----------------------------------------------
> # γ補正されたRGBから16進文字列を作り色指定に使う
> sRGBhex <- rgb(64, 128, 192, maxColor=255)
> sRGBhex 
[1] "#4080C0"
> # デフォルトは0-1の値になっているが、γ補正されたRGBに変わりない
> sRGBhex <- rgb(64/255, 128/255, 192/255)
> sRGBhex 
[1] "#4080C0"
> # ColorSpaceパッケージのRGB ---------------------------------------
> # 16進文字列の色(Rの基本的な色表現)からColorSpaceのRGBに変換
> cs_RGB <- hex2RGB("#4080C0")
> cs_RGB # リニアRGB
              R         G         B
[1,] 0.06567053 0.2452781 0.5560067
> # 16進文字列に復元を確認
> hex(cs_RGB) # 復元を確認
[1] "#4080C0"
> # 0-1のR,G,Bを指定して、ColorSpaceのRGBを作る
> cs_RGB2 <- RGB(cs_RGB@coords[1],cs_RGB@coords[2],cs_RGB@coords[3])
> cs_RGB2
              R         G         B
[1,] 0.06567053 0.2452781 0.5560067
> # ColorSpaceのRGBで指定する、R,G,Bはγ補正されたRGBではない
> sRGB2 <- RGB(64/255, 128/255, 192/255)
> sRGB2 # γ補正されたRGBの0-1表現
             R         G         B
[1,] 0.2509804 0.5019608 0.7529412
> # γ補正の逆演算をしてからColorSpaceのRGBに(2.4だと合わない)
> lR <- (( 64/255+0.055)/1.055)^2.4
> lG <- ((128/255+0.055)/1.055)^2.4
> lB <- ((192/255+0.055)/1.055)^2.4
> sRGB3 <- RGB(lR, lG, lB)
> sRGB3 
              R         G         B
[1,] 0.05126946 0.2158605 0.5271151
> hex(sRGB3) # 復元しない
[1] "#3878BB"
> # γ補正の逆演算をしてからColorSpaceのRGBに(2.2で一致)
> lR2 <- (( 64/255+0.055)/1.055)^2.2
> lG2 <- ((128/255+0.055)/1.055)^2.2
> lB2 <- ((192/255+0.055)/1.055)^2.2
> sRGB4 <- RGB(lR2, lG2, lB2)
> sRGB4
              R         G         B
[1,] 0.06567053 0.2452781 0.5560067
> hex(sRGB4) # 復元を確認
[1] "#4080C0"
>

 

13.L*a*b*で色の分布を見る

おなじ物をRGBからL*a*b*に変換して、分布を見てみました。
グレースケール化もL*a*b*化も、RGBに対して四則を施したもので本質的な差はないのでしょうが、わたしにはRGBではイメージできませんので。

   
  

全データのでは境目は分かりませんが、度数が60超をプロットすると、下図になります。

   
 

各面を見るとなんとなく左右に分割されているように見えます。この左右はどんなことを表すのか、左右を分離して見ました。

  a=3  b=-10  a=10
 左    
 左    

 

 

 L*を2値化してみました。
下段は、元の画像をグレースケール化してから2値化したものです。

  

(100,0,0)からの 色差を計算し、この差に離隔抽出フィルタを適用して見ます。注目点と左、左上、上の4点で行います。負の値が白への変化なので、色差が-3以下の点を白の候補にします。この候補の度数分布を見て閾値を決めます。
全体を一度に計算するのはあきらめて、着目部分ごとに異なる閾値を使います。

  

  

 

 

##############################################################
# 特徴的な部分を分割してファイルにしておいてから
source("Bitmap_R.R")
img <- bm_read("11.bmp")
cols <- rgb(img$rgb[1,],img$rgb[2,],img$rgb[3,],maxColor=255)
rgbc <- hex2RGB(cols)
labc <- as(rgbc,"LAB")
# 各ピクセルの白(1,0,0)からの距離を計算
labd <- array(0,c(img$width, img$height))
i <- 1
for( y in 1:img$height) for( x in 1:img$width) {
  labd[x,y] <- sqrt((labc@coords[i,1]-100)^2 + labc@coords[i,2]^2 + labc@coords[i,3]^2)
  i <- i + 1
}
range(labd)
windows(4,4)
hist(labd,breaks=50,main="白からの色差の度数")
# 左上近傍 ラプラシアンフィルタで輪郭を見つける
edge <- array(0,c(img$width, img$height))
for( y in 2:img$height) for( x in 2:img$width) { 
  edge[x,y] <- labd[x,y]*(-3) + labd[x-1,y] + labd[x,y-1] + labd[x-1,y-1]
}
range(edge)
# この値が負であればその位置は白と判断する。色差3で区別して、白を集める
white <- labd[edge< -3]
range(white)
windows(4,4)
hist(white,breaks=50,main="白への変化点の色差の度数")
length(white)
length(edge)

e <- as.vector(edge)
windows(4,4)
b <- matrix(0,nrow=3,ncol=length(img$rgb[1,]))
b[1,] <- ifelse(labd<=43,255,img$rgb[1,])
b[2,] <- ifelse(labd<=43,255,img$rgb[2,])
b[3,] <- ifelse(labd<=43,255,img$rgb[3,])
bm_image(b,img$width,img$height,main="閾値:白からの色差43")

 

 

 


千葉市 不動産 検索エンジン登録 美容外科 札幌 ステップワゴン プリウス