目錄
圖像變換介紹
?用Halcon自帶的算子實現(xiàn)圖像變換
使用矩陣來實現(xiàn)相關(guān)算子的功能
一、平移
二、旋轉(zhuǎn)
三、縮放
四、鏡像
完整代碼
????????在halcon中經(jīng)常會用到圖像變換的操作,然后這次作業(yè)是用矩陣來實現(xiàn)相關(guān)算子的功能,學(xué)到了挺多的所以就記錄下來方便復(fù)習(xí)。
圖像變換介紹
????????基礎(chǔ)部分可以看這篇文章,寫的挺好的
深入淺出HALCON幾何變換https://www.51halcon.com/forum.php?mod=viewthread&tid=1466
?用Halcon自帶的算子實現(xiàn)圖像變換
????????在學(xué)習(xí)矩陣先用算子實現(xiàn)一遍,畢竟這些封裝好算子才是高頻使用的東西,而且也可以方便
接下來自己實現(xiàn)時比對效果
read_image (Image, 'datacode/ecc200/ecc200_to_preprocess_001.png')
hom_mat2d_identity (HomMat2DIdentity)
*平移
hom_mat2d_translate (HomMat2DIdentity, 64, 64, HomMat2DTranslate)
affine_trans_image (Image, ImageAffineTrans, HomMat2DTranslate, 'constant', 'false')
*縮放
hom_mat2d_scale (HomMat2DIdentity, 2, 2, 0, 0, HomMat2DScale)
affine_trans_image (Image, ImageAffineTrans1, HomMat2DScale, 'constant', 'false')
*旋轉(zhuǎn)
hom_mat2d_rotate (HomMat2DIdentity, 0.78, 0, 0, HomMat2DRotate)
affine_trans_image (Image, ImageAffineTrans2, HomMat2DRotate, 'constant', 'false')
*鏡像
get_image_size (Image, Width, Height)
hom_mat2d_reflect (HomMat2DIdentity, 0, Width/2, 10, Width/2 , HomMat2DReflect1)
affine_trans_image (Image, ImageAffineTrans3, HomMat2DReflect1, 'constant', 'false')
? ? ? ? 這里我提一嘴hom_mat2d_reflect的第2到第5個的參數(shù)。這其實是兩個坐標(biāo)點,halcon根據(jù)這兩個坐標(biāo)形成的線來當(dāng)作對稱軸。比如我這里的坐標(biāo)點是(0, Width/2)和(10, Width/2),也就是圖像列的中點,所以圖像會左右鏡像。
????????順便一提,這個圖片是halcon自帶的,打開read_image的算子窗口點擊文件夾的圖標(biāo)就可以找到你的halcon的圖片存放的路徑,上面我已經(jīng)改成相對路徑所以應(yīng)該可以直接運行
使用矩陣來實現(xiàn)相關(guān)算子的功能
一、平移
????????基本的思路是將圖像的每個坐標(biāo)和矩陣相乘得到新的坐標(biāo),然后將舊坐標(biāo)的像素值賦與新坐標(biāo)
????????首先創(chuàng)建一個矩陣
*平移
*[1,0,x,\
*0,1,y,\
*0,0,1]
create_matrix (3, 3, [1,0,64,\
0,1,64,\
0,0,1], MatrixID)
????????平移矩陣形式如上,x和y分別是你在x軸和y軸上的平移量。
????????然后遍歷圖片,將每個坐標(biāo)與矩陣相乘,在這里我們先創(chuàng)建一個新的空圖像,然后將變換后的圖輸入到新圖像中,這樣就不會覆蓋原圖
*使用gen_image_const 創(chuàng)建一個空圖像
get_image_size (Image, Width, Height)
gen_image_const (Imageout, 'byte', Width, Height)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
*得到原圖的坐標(biāo)點的像素值
get_grayval (Image, x, y, Grayval)
*將坐標(biāo)轉(zhuǎn)化為矩陣形式以用于矩陣相乘
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*平移
mult_matrix (MatrixID, MatrixID1, 'AB', MatrixMultID)
*得到矩陣的值,Values[0]是x,Values[1]是y
get_full_matrix (MatrixMultID, Values)
*邊界處理
if (Values[0] >= 0 and Values[0] <Height and\
Values[1] >= 0 and Values[1] <Width)
*將矩陣的值賦與新圖像
set_grayval (Imageout, Values[0], Values[1], Grayval)
endif
endif
endfor
endfor
????????因為我們圖像大小是400*400的,所以根據(jù)這張圖像創(chuàng)建的新圖像大小也是400*400的。當(dāng)它平移后超過圖像大小范圍的地方要被裁剪。如果你不想裁剪圖像,那么創(chuàng)建新圖像時就要考慮到平移的長度。
????????如上,左側(cè)是原圖,中間紅色區(qū)域是圖像的域,也就是圖像的大小,右側(cè)是平移后的圖像。可以看到圖像超出紅色區(qū)域的部分被裁剪。
二、旋轉(zhuǎn)
????????旋轉(zhuǎn)的思路和平移略有不同,如果直接遍歷原圖你會得到這樣的結(jié)果
左圖為正常結(jié)果圖像,右圖為遍歷原圖得到的圖像
????????出現(xiàn)這種結(jié)果是因為當(dāng)你用矩陣去乘圖像時很可能得不到某些點的坐標(biāo),因此這些點不會被賦值,自然就會出現(xiàn)空洞。
????????用下面的代碼測試
*由圖可知在點(1,3)處有空洞,遍歷原圖,讓程序在點(1,3)處停止,
*如果沒有停止則代表該點沒有出現(xiàn)過
mult_matrix (MatrixID2, MatrixID1, 'AB', MatrixMultID2)
get_full_matrix (MatrixMultID2, Values2)
if (Values2[0] >= 1 and Values2[0] <2 and\
Values2[1] >= 3 and Values2[1] <4)
stop ()
endif
查過資料后才知道,為防止空洞出現(xiàn)一般用反解法。所謂反解法就是不遍歷原圖,而是遍歷結(jié)果圖,這樣就可以保證結(jié)果圖上的每一個點都有數(shù)值,防止空洞現(xiàn)象出現(xiàn)。
????????如圖所示,一般情況我們是遍歷原圖來得到結(jié)果圖,就是①的思路,但原圖上的坐標(biāo)點并不和結(jié)果圖一一對應(yīng),也就是說原圖上的(2,3)未必就落在結(jié)果圖的(2,3)上(一樣的話你也實現(xiàn)不了旋轉(zhuǎn)的效果╮(╯▽╰)╭)
? ? ? ? 現(xiàn)在轉(zhuǎn)變一下思路,既然原圖上的點無法一一映射到結(jié)果圖上,那么不妨用結(jié)果圖一一映射到原圖上去,也就是②的思路:通過遍歷結(jié)果圖的坐標(biāo),在原圖上去尋找對應(yīng)的像素值。這就是反解法。
? ? ? ? 可能還會有人有疑惑,所以我再啰嗦一點。兩張圖之間的對應(yīng)關(guān)系來源于你的矩陣,而矩陣運算結(jié)果未必就包括了所有的點,所以正推時出現(xiàn)的空洞就是結(jié)果中沒有包含的點。而反推時其實也沒有用到原圖的所有點,比如原圖是400X400的大小共160,000個像素值,結(jié)果圖中比如就用了15萬個點的值,那么剩下1萬多個點就是矩陣運算中沒有計算到的點的地方了。所以其實只用反解法的話效果未必會好,這也是為什么需要用線性插值的原因了。
? ? ? ? 那么說完為什么用反解法后,就是怎么用反解法了。我們可以先從數(shù)學(xué)角度來看
? ? ? ? 其中,Y是結(jié)果圖的坐標(biāo)矩陣,X是原圖的坐標(biāo)矩陣,A則是旋轉(zhuǎn)矩陣,A(-1)則是A的逆矩陣。一般我們是已知X和A要求Y,但現(xiàn)在我們使用反解法,故此是已知Y和A要求X,簡單推導(dǎo)后可以得到上式。所以反解法說著好聽,其實就是用A的逆矩陣來乘就行了,代碼如下。
*旋轉(zhuǎn)
create_matrix (3, 3, [cos(rad(45)),-sin(rad(45)),0,\
sin(rad(45)),cos(rad(45)),0,\
0,0,1], MatrixID2)
*使用反解法故需得到逆矩陣
invert_matrix (MatrixID2, 'general', 0, MatrixInvID)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
*得到原圖的坐標(biāo)點的像素值
get_grayval (Image, x, y, Grayval)
*將坐標(biāo)轉(zhuǎn)化為矩陣形式以用于矩陣相乘
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*旋轉(zhuǎn)
mult_matrix (MatrixInvID, MatrixID1, 'AB', MatrixMultID2)
get_full_matrix (MatrixMultID2, Values2)
endif
endfor
endfor
????????這樣一來我們就得到我們想要的值Values2。當(dāng)然就如上面所說,反解法得到的結(jié)果未必就好,多數(shù)情況下我們還需要使用線性插值的辦法來得到最佳的結(jié)果
? ? ? ? 有關(guān)線性插值我們可以參考下面這一篇,我覺得講的還挺好的
雙線性插值原理詳解及代碼實現(xiàn) - kkjz的文章
????????根據(jù)大佬的思路創(chuàng)建下面兩個函數(shù),然后直接用就行了
*函數(shù)一:線性插值single_biline
*x:輸入點坐標(biāo),x1,x2:已知點坐標(biāo),p1,p2:已知點像素值,p:輸入點像素值
al := abs(x2 - x)
p := al*p1 + (1 - al)*p2
*函數(shù)二:雙線性插值double_biline
*邊界處理
get_image_size (Image, Width, Height)
if (Value_x < 0 or Value_y< 0 or\
Value_x > Height - 1 or Value_y> Width - 1)
pout := -1
return ()
endif
*得到x軸的相鄰點
tuple_floor (Value_x, x1)
x1 := int (x1)
tuple_ceil (Value_x, x2)
x2 := int (x2)
*得到y(tǒng)軸的相鄰點
tuple_floor (Value_y, y1)
y1 := int (y1)
tuple_ceil (Value_y, y2)
y2 := int (y2)
*得到點的像素值
get_grayval (Image, x1, y1, p1)
get_grayval (Image, x2, y1, p2)
get_grayval (Image, x1, y2, p3)
get_grayval (Image, x2, y2, p4)
*雙線性插值
single_biline (Value_x, x1, x2, p1, p2, p12)
single_biline (Value_x, x1, x2, p3, p4, p34)
single_biline (Value_y, y1, y2, p12, p34, pout)
????????完整代碼如下
*旋轉(zhuǎn)
create_matrix (3, 3, [cos(rad(45)),-sin(rad(45)),0,\
sin(rad(45)),cos(rad(45)),0,\
0,0,1], MatrixID2)
*使用反解法故需得到逆矩陣
invert_matrix (MatrixID2, 'general', 0, MatrixInvID)
get_image_size (Image, Width, Height)
gen_image_const (Imageout2, 'byte', Width, Height)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*旋轉(zhuǎn)
mult_matrix (MatrixInvID, MatrixID1, 'AB', MatrixMultID2)
get_full_matrix (MatrixMultID2, Values2)
double_biline (Image, Values2[0], Values2[1], pout)
if (pout == (-1))
continue
endif
set_grayval (Imageout2, x, y, pout)
endfor
????????在這里我的邊界處理和大佬不同,我是直接將越界的值直接continue掉。因為我這里原圖和結(jié)果圖的域是相同的,所以結(jié)果圖中有些地方不存在值,直接continue掉了。
三、縮放
????????縮放與旋轉(zhuǎn)思路一樣,只是矩陣不同而已,所以我就直接貼代碼了
*縮放,x和y分別是x軸和y軸的縮放倍率
*[x,0,0,\
*0,y,0,\
*0,0,1]
create_matrix (3, 3, [2,0,0,\
0,2,0,\
0,0,1], MatrixID3)
invert_matrix (MatrixID3, 'general', 0, MatrixInvID1)
get_image_size (Image, Width, Height)
gen_image_const (Imageout3, 'byte', Width, Height)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*縮放
mult_matrix (MatrixInvID1, MatrixID1, 'AB', MatrixMultID3)
get_full_matrix (MatrixMultID3, Values3)
get_grayval (Image,Values3[0], Values3[1], Grayval1)
set_grayval (Imageout3, x, y, Grayval1)
double_biline (Image, Values3[0], Values3[1], pout2)
if (pout2 == (-1))
continue
endif
set_grayval (Imageout3,x,y, pout2)
endfor
endfor
四、鏡像
????????鏡像與平移同理,不過鏡像矩陣我是直接抄的hom_mat2d_reflect的矩陣,感興趣可以自行研究文章來源:http://www.zghlxwxcb.cn/news/detail-854392.html
*鏡像
get_image_size (Image, Width, Height)
create_matrix (3, 3, [1,0,0,\
0,-1,Width,\
0,0,1], MatrixID4)
get_image_size (Image, Width, Height)
gen_image_const (Imageout4, 'byte', Width, Height)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
get_grayval (Image, x, y, Grayval)
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*鏡像
mult_matrix (MatrixID4, MatrixID1, 'AB', MatrixMultID4)
get_full_matrix (MatrixMultID4, Values4)
if (Values4[0] >= 0 and Values4[0] <Height and\
Values4[1] >= 0 and Values4[1] <Width)
set_grayval (Imageout4, Values4[0], Values4[1], Grayval)
endif
endfor
endfor
完整代碼
read_image (Image, 'datacode/ecc200/ecc200_to_preprocess_001.png')
* read_image (Image, 'claudia.png')
* rgb1_to_gray (Image, Image)
hom_mat2d_identity (HomMat2DIdentity)
get_domain (Image, Domain)
*平移
hom_mat2d_translate (HomMat2DIdentity, 64, 64, HomMat2DTranslate)
affine_trans_image (Image, ImageAffineTrans, HomMat2DTranslate, 'constant', 'false')
*縮放
hom_mat2d_scale (HomMat2DIdentity, 2, 2, 0, 0, HomMat2DScale)
affine_trans_image (Image, ImageAffineTrans1, HomMat2DScale, 'constant', 'false')
*旋轉(zhuǎn)
hom_mat2d_rotate (HomMat2DIdentity, 0.78, 0, 0, HomMat2DRotate)
affine_trans_image (Image, ImageAffineTrans2, HomMat2DRotate, 'constant', 'false')
*鏡像
get_image_size (Image, Width, Height)
hom_mat2d_reflect (HomMat2DIdentity, 0, Width/2, 10, Width/2 , HomMat2DReflect1)
affine_trans_image (Image, ImageAffineTrans3, HomMat2DReflect1, 'constant', 'false')
*tuple實現(xiàn)變換
dev_update_off ()
*平移
create_matrix (3, 3, [1,0,64,\
0,1,64,\
0,0,1], MatrixID)
*旋轉(zhuǎn)
create_matrix (3, 3, [cos(rad(45)),-sin(rad(45)),0,\
sin(rad(45)),cos(rad(45)),0,\
0,0,1], MatrixID2)
*使用反解法故需得到逆矩陣
invert_matrix (MatrixID2, 'general', 0, MatrixInvID)
*縮放
create_matrix (3, 3, [2,0,0,\
0,2,0,\
0,0,1], MatrixID3)
invert_matrix (MatrixID3, 'general', 0, MatrixInvID1)
*鏡像
get_image_size (Image, Width, Height)
create_matrix (3, 3, [1,0,0,\
0,-1,Width,\
0,0,1], MatrixID4)
get_image_size (Image, Width, Height)
gen_image_const (Imageout, 'byte', Width, Height)
gen_image_const (Imageout2, 'byte', Width, Height)
gen_image_const (Imageout3, 'byte', Width, Height)
gen_image_const (Imageout4, 'byte', Width, Height)
for x := 0 to Height - 1 by 1
for y := 0 to Width - 1 by 1
get_grayval (Image, x, y, Grayval)
create_matrix (3, 1, [x,\
y,\
1], MatrixID1)
*平移
mult_matrix (MatrixID, MatrixID1, 'AB', MatrixMultID)
get_full_matrix (MatrixMultID, Values)
if (Values[0] >= 0 and Values[0] <Height and\
Values[1] >= 0 and Values[1] <Width)
set_grayval (Imageout, Values[0], Values[1], Grayval)
endif
*旋轉(zhuǎn)
mult_matrix (MatrixInvID, MatrixID1, 'AB', MatrixMultID2)
get_full_matrix (MatrixMultID2, Values2)
double_biline (Image, Values2[0], Values2[1], pout)
if (pout != (-1))
set_grayval (Imageout2, x, y, pout)
endif
*縮放
mult_matrix (MatrixInvID1, MatrixID1, 'AB', MatrixMultID3)
get_full_matrix (MatrixMultID3, Values3)
double_biline (Image, Values3[0], Values3[1], pout2)
if (pout2 != (-1))
set_grayval (Imageout3,x,y, pout2)
endif
*鏡像
mult_matrix (MatrixID4, MatrixID1, 'AB', MatrixMultID4)
get_full_matrix (MatrixMultID4, Values4)
if (Values4[0] >= 0 and Values4[0] <Height and\
Values4[1] >= 0 and Values4[1] <Width)
set_grayval (Imageout4, Values4[0], Values4[1], Grayval)
endif
endfor
endfor
相關(guān)函數(shù)代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-854392.html
*函數(shù)一:線性插值single_biline
*x:輸入點坐標(biāo),x1,x2:已知點坐標(biāo),p1,p2:已知點像素值,p:輸入點像素值
al := abs(x2 - x)
p := al*p1 + (1 - al)*p2
*函數(shù)二:雙線性插值double_biline
*邊界處理
get_image_size (Image, Width, Height)
if (Value_x < 0 or Value_y< 0 or\
Value_x > Height - 1 or Value_y> Width - 1)
pout := -1
return ()
endif
*得到x軸的相鄰點
tuple_floor (Value_x, x1)
x1 := int (x1)
tuple_ceil (Value_x, x2)
x2 := int (x2)
*得到y(tǒng)軸的相鄰點
tuple_floor (Value_y, y1)
y1 := int (y1)
tuple_ceil (Value_y, y2)
y2 := int (y2)
*得到點的像素值
get_grayval (Image, x1, y1, p1)
get_grayval (Image, x2, y1, p2)
get_grayval (Image, x1, y2, p3)
get_grayval (Image, x2, y2, p4)
*雙線性插值
single_biline (Value_x, x1, x2, p1, p2, p12)
single_biline (Value_x, x1, x2, p3, p4, p34)
single_biline (Value_y, y1, y2, p12, p34, pout)
到了這里,關(guān)于Halcon用矩陣實現(xiàn)圖像變換(平移,旋轉(zhuǎn),縮放,鏡像等)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!