Friday, April 16, 2010

Learning OpenCV: Histogram

คงรู้จักกันดีว่า histogram คืออะไร มาดูการใช้งานใน OpenCV เลยดีกว่า

ใน OpenCV เราสร้าง histogram ด้วยคำสั่ง

CvHistogram* cvCreateHist(
    int dims,
    int* sizes,
    int type,
    float** ranges = NULL,
    int uniform = 1
);

dims คือจำนวนมิติของ histogram
sizes คือขนาดในแต่ละมิติ
type อาจะเป็น CV_HIST_ARRAY เพื่อเก็บข้อมูล histogram ใน dense multidimensional matrix structure (CvMatND) หรือ CV_HIST_SPARSE เพื่อเก็บข้อมูล histogram ใน sparse matrix representation (CvSparseMat)
uniform บอกว่า ข้อมูลใน bins (แต่และช่องของ histogram) เป็น uniform หรือไม่ และยังมีผลต่อความหมายของพารามิเตอร์ ranges  ถ้าตั้งค่าไม่เท่ากับศูนย์ bins จะ uniform
ranges ในกรณีที่ uniform=1 ranges เป็น array ของค่าคู่ลำดับ จำนวนคู่ลำดับจะเท่ากับจำนวนมิติ ในกรณี uniform =0 จะเป็นอะเรย์ของช่วงของแต่ละมิติ (งงล่ะสิ ดูตัวอย่างโลด)


uniform = 1 dims=1 (histogram 1 มิติ) sizes[0]=2  ranges[0] = [0,10]
จะหมายถึง histogram 1 มิติ มี 2 bins bin แรกเก็บค่า [0,5) bin สองเก็บค่า [5,10]


uniform = 0 dims=1 (histogram 1 มิติ) sizes[0]=5 ranges[0]=[0,2,4,5,7,12]
จะหมายถึง histogram 1 มิติ 5 bins  เก็บค่า [0,2), [2,4), [4,5), [5,7) ,[7,12]

เราสามารถให้ OpenCV ตั้ง range ได้โดยใช้คำสั่ง cvSetHistRanges  และเราสามารถ clear histogram เพื่อนับค่าใหม่ได้โดยใช้คำสั่ง cvCreateHist และ release histogram โดยใช้คำสั่ง cvReleaseHist 


Accessing Histogram
OpenCV มีฟังก์ชันในการเข้าถึงข้อมูลใน historgram อยู่สองชุด

  1. cvQueryHistValue_1D, cvQueryHistValue_2D, cvQueryHistValue_nD
  2. cvGetHistValue_1D, cvGetHistValue_2D, cvGetHistValue_nD
ถ้าต้องการเข้าถึงข้อมูลตรงเพื่อประสิทธิภาพ เราก็สามารถเข้าถึงข้อมูลโดยตรงได้ โดยอ้างถึง CvHistogram ก่อนอื่นมาดู struct ของ histogram กันก่อน

typedef struct CvHistogram
{
    int type;
    CvArr* bins;
    float thresh[CV_MAX_DIM][2]; // for uniform histograms
    float** thresh2; // for nonuniform histograms
    CvMatND mat; // embedded matrix header
     // for array histograms
}
CvHistogram;

ในกรณีที่เป็น sparse histogram mat น่าจะเป็น CvSparseMat 

ยกตัวอย่างในกรณีที่่ histogram เป็นแบบ dense ข้อมูลของ histogram จะเก็บในข้อมูล CvMatND เราก็สามารถอ้างถึงข้อมูลตรงนี้ได้ เช่น
  • หาจำนวนมิติได้ โดยใช้ histogram->mat.dims
  • หาจำนวน bins ในมิติ i โดยใช้ histogram->dim[i].size;
  • ในกรณี uniform หา lower, upper bound ของ bin ในมิติ ที่ i โดย histogram->thresh[ i ][ 0 ], histogram->thresh[ i ][ 1 ]
  • ในกรณี non uniform หา lower, upper bound ของ bin j ในมิติที่ i โดย histogram->thresh2[ i ][ j ], histogram->thresh2[ i ][ j +1]


Basic Manipulations with Histograms


ขั้นตอนที่สำคัญเกี่ยวกับ histogram จริงน่าจะเป็นการเก็บข้อมูลใน histogram และนำไปวิเคราะห์มากว่า
ในส่วนนี้จะสรุปเนื้อหาคร่าวในการสร้าง histogram เพื่อนำไปใช้ในการประมวลผล

เริ่มต้นที่การสร้าง histogram จาก image กันก่อน ด้วยคำสั่ง


void cvCalcHist(
    IplImage** image,

    CvHistogram* hist,
    int accumulate = 0,
    const CvArr* mask = NULL
);

image เป็นภาพที่ต้องการหา histogram (channel เดียวเท่านั้น) (จริงๆ ใช้ CvMat ก็ได้)
hist ผลลัพธ์
accumulate จะตั้งว่าให้เคลียร์ histogram ใหม่หรือไม่(ในกรณีต้องการคำนวณ histogram รวมหลายๆ ภาพ)
mask จะกำหนด pixel ที่จะคำนวณ histogram ถ้าไม่ระบุก็จะหมายถึงทุก pixel

หลังจากคำนวณ histogram แล้วเราสามารถใช้คำสั่งเหล่านี้เพื่อ manipulate histogram ได้

  • cvCopyHist  สำเนาค่าไปยัง histogram ใหม่
  • cvGetMinMaxHistValue หาค่าสูงสุดต่ำสุดของ histogram
  • cvThreshHist ตัดค่าใน bin ที่น้อยกว่า threshold ให้เป็น 0
  • cvNormalizeHist normalize histogram



No comments:

Post a Comment