C#影象顏色域判斷以及顏色直方圖識別方法
顏色特徵的提取
由於該演算法會將很多圖片,尤其是人臉識別為海邊風景,我們首先添加了一個限制條件。取典型的海顏色亮藍色,其RGB值分別為0≤R≤100,100≤G≤255,150≤B≤255,當亮藍色顏色區域超過影象區域3%的時候才進行下一步提取影象顏色直方圖。否則就不是海邊風景型別。
先提取輸入影象的顏色特徵,即統計影象中每種顏色的畫素的數目。在本軟體中,使用GetPixel()對影象按畫素提取顏色資訊。但是,對24位的RGB影象來說,其顏色空間(即不同的顏色數目)是224=256×256×256=16777216。在實際應用中, 若直接選用此值,資料量巨大, 特徵提取緩慢, 同時也會使特徵庫非常龐大。為此, 可將顏色空間等距離分組(在該系統中分為16000種顏色值)取值,然後再統計每組中對應的畫素數目,從而得到整個影象的顏色直方圖, 這樣, 影象的顏色直方圖可以存在一個有16000個元素陣列中。
2.1.2 影象相似度的度量
比較兩幅影象是否相似,就是計算兩幅影象的歐式距離。假設輸入影象的直方圖用G(g1,g2…… ,gN) 表示,資料庫中的標準影象直方圖用S(s1,s2,……sN) 表示,可以將這兩個直方圖看作歐氏空間的兩個點,利用歐氏距離來描述它們的相似性,即:Ed(G,S)= ,其中N 為顏色級數,Ed(G,S)的值越接近0,則兩幅影象越相似。如果兩幅影象完全一致,則Ed(G,S)=0。在本系統中,則是兩個分別代表輸入影象和標準影象的顏色直方圖的陣列,按照上述公式計算距離d,當d<0.07時,認為輸入圖片與標準圖片是相似的,可以把輸入圖片歸類到標準圖片的一類。
2.2 優缺點分析
l 演算法簡單易於理解,同時執行效率很高;
l 加入2.1.1的第一條限制條件後,對輸入圖片的判斷成功率很高;
l 對於非藍色為主的海景,如黃昏或者晚上的海景以及沙灘等不能成功識別,藍色為主的圖片也會導致誤識別。
2.3 可做的改進與擴充套件
l 可以採用多張標準圖片,擴充套件可識別圖片的範圍;
l 可用同樣的顏色識別方法擴充套件做出森林、山水、雪山等風景圖片,或者夜景、黃昏景色等型別圖片的識別和檢索,但是要加上相應的紋理判斷和更多條件才能保證識別的準確性。
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Diagnostics;
namespace Readimage3
{
public class ColorAnalysis//此類實現影象顏色直方圖提取與匹配演算法,方法為與標準影象的顏色直方圖特徵向量對比,通過計算兩幅直方圖之間的歐氏距離來描述它們之間的相似性,選出與標準圖片相似的圖片,主要用於海邊風景的識別
{
//用於檢索顏色相似的演算法所宣告的變數
int i, j;
string c11, c22;
int r = 16000, n1, m11, m1, n2, m22, m2;
Color c1 = new Color();
Color c2 = new Color();
public double ColorValue(Image p,Image pS1)//通過與標準影象顏色分佈進行對比,並返回顏色分佈相似值
{
//變數宣告以及初始化
double[,] s1 = new double[20000, 2];
double[,] s2 = new double[20000, 2];
double seaBlue=0;//海藍色畫素點數
double percent;//海藍色佔影象比率
double u = 0, d;
string D = " ";
u = 0;
n1 = 0;
m11 = 0;
m1 = 0;
n2 = 0;
m22 = 0;
m2 = 0;
Form1 f=new Form1();
//計算開啟的圖片畫素分佈
if (p != null)
{
Bitmap p1 = new Bitmap(p);
for (i = 0; i < p1.Width - 1; i++)
{
for (j = 0; j < p1.Height - 1; j++)
{
c1 = p1.GetPixel(i, j); //獲得影象每點的顏色基本屬性
if (c1.R >= 0 && c1.R <= 100 && c1.G >= 100 && c1.G <= 255 && c1.B >= 150 && c1.B <= 255)//判斷顏色是否為海藍色區域
seaBlue++;
n1 = n1 + 1; //統計畫素數
c11 = c1.Name; //返回RGB 值
m1 = Convert.ToInt32(Math.Pow(256, 3) / r); //每組顏色值的範圍,這裡設定組數為16000,可以擴大組數以提高精度,但會降低識別速度。
string str = c11;
//將十六進位制裝換成十進位制
int val = (-1) * Int32.Parse(str, System.Globalization.NumberStyles.HexNumber);
m11 = Convert.ToInt32(Math.Floor(Convert.ToDouble(val / m1))); //提取顏色歸屬於哪一組
s1[m11, 0]++; //統計每組顏色的畫素數
}
}
//用於對比的標準圖片
Bitmap p2 = new Bitmap(pS1);
for (i = 0; i < p2.Width - 1; i++)
{
for (j = 0; j < p2.Height - 1; j++)
{
c2 = p2.GetPixel(i, j); //獲得影象每點的顏色基本屬性
n2 = n2 + 1; //統計畫素數
c22 = c2.Name; //返回RGB 值
m2 = Convert.ToInt32(Math.Pow(256, 3) / r); //每組顏色值的範圍
string str = c22;
//將十六進位制裝換成十進位制
int val = (-1) * Int32.Parse(str, System.Globalization.NumberStyles.HexNumber);
m22 = Convert.ToInt32(Math.Floor(Convert.ToDouble(val / m2))); //提取顏色歸屬於哪一組
s2[m22, 0]++; //統計每組顏色的畫素數
}
}
for (i = 0; i < 16000; i++)
{
u += (Convert.ToDouble((s1[i, 0] - s2[i, 0]) / n1)) * (Convert.ToDouble((s1[i, 0] - s2[i, 0]) / n1));
}
percent = seaBlue / n1;
if (percent > 0.03)//海藍色比率大於0.03再進行d值的判斷,否則直接跳過d值的計算
{
d = Math.Pow(u, 0.5);
D = String.Format("{0:F6}", d);
return d;
}
else
return d = 1;
}
else
return d=1;
}