本篇為原創,僅僅作為學習參考之用,轉載請說明。
一.題目描述:
在二維觀察中,需要在觀察坐標系下根據窗口大小對二維圖形進行裁剪(clipping),只將位於窗口內的圖形變換到視區輸出。
直線段裁剪是二維圖形裁剪的基礎,裁剪的實質是判斷直線段是否與窗口相交,如相交則進一步確定直線段上位於窗口內的部分。
那么怎么進行裁剪,首先要定義一下窗口內及窗口外的編碼,每段直線的端點都被賦予一組四位二進制代碼,
稱為區域編碼(region code,RC),用來標識直線段端點相對於窗口邊界及其延長線的位置。如圖
為了保證窗口內及窗口邊界上直線段端點的編碼為零,定義規則如下:
C0:若端點的x<wxl,則C0=1,否則C0=0。
C1:若端點的x>wxr,則C1=1,否則C1=0。
C2:若端點的y<wyb,則C2=1,否則C2=0。
C3:若端點的y>wyt,則C3=1,否則C3=0。
二.算法思路:
1.將直線起點p1和終點p2進行編碼得到code1和code2.。
2.若兩端點編碼值均為0,說明直線段在窗口內,保留。
3.若兩端點編碼值code1&code2!=0,則說明直線段位於窗外的同一側,或左方、或右方、或上方、或下方,拋棄。
4.若code1&code2==0,則直線段必然與窗口邊界或窗口邊界的延長線相交,此時該進行求交點操作。
任取編碼值不為0的其中一點p1(該點必然在窗口外),然后用p1的編碼值與窗口之外左右下上的編碼值進行按位與&運算,
如果結果不為0,則直線段與窗口該側的邊界有交點,根據直線起點和終點求出交點。
將交點進行編碼,把編碼值賦給p1,則此時p1位於窗口邊界上,即交點成為直線段起點,相當於舍去原來的p0與交點的那個線段,形成一個新的線段p1p2,
再次重復以上步驟,若皆在窗口中,則保留;否則繼續循環,直到直線段全部位於窗口內為止。
三.注意事項
如果想繪制出圖形的話要自己學習python的圖形庫哦,這里我用的是OpenCV庫。首先建立畫布,畫出矩形窗口區域,然后才開始裁剪算法的,
這里裁剪的實質是判斷直線的哪些部分在窗口內部,然后繪制出它們,窗口之外的部分就忽略。
四.代碼

1 import numpy as np 2 import cv2 3 4 LEFT = 1 5 RIGHT = 2 6 BOTTOM = 4 7 TOP = 8 8 9 xl = 300 10 xr = 500 11 yb = 150 12 yt = 350 # 窗口的邊界值 13 14 # Create a black image 15 img = np.zeros((500, 800, 3), np.uint8) # 相當於建立畫布 16 17 18 # 編碼 19 def encode(x, y): 20 c = 0 21 if x < xl: 22 c = c | LEFT 23 if x > xr: 24 c = c | RIGHT 25 if y < yb: 26 c = c | BOTTOM 27 if y > yt: 28 c = c | TOP 29 return c 30 31 32 # cohen-sutherland 算法 33 def CohenSutherland(x1, y1, x2, y2): 34 code1 = encode(x1, y1) 35 code2 = encode(x2, y2) 36 outcode = code1 # outcode是總在窗口外的那個端點 37 x, y = 0, 0 38 area = False # 設置一個是否滿足條件的區分標志 39 while True: 40 if (code2 | code1) == 0: 41 area = True 42 break 43 if (code1 & code2) != 0: # 簡棄之 44 break 45 if code1 == 0: # 開始求交點 46 outcode = code2 47 if (LEFT & outcode) != 0: # 與窗口左邊界相交 48 x = xl 49 y = y1 + (y2 - y1) * (xl - x1) / (x2 - x1) 50 elif (RIGHT & outcode) != 0: 51 x = xr 52 y = y1 + (y2 - y1) * (xr - x1) / (x2 - x1) 53 elif (BOTTOM & outcode) != 0: 54 y = yb 55 x = x1 + (x2 - x1) * (yb - y1) / (y2 - y1) 56 elif (TOP & outcode) != 0: 57 y = yt 58 x = x1 + (x2 - x1) * (yt - y1) / (y2 - y1) 59 x = int(x) # 轉換為整型 60 y = int(y) 61 if outcode == code1: 62 # print('hhh') # 測試用 63 x1 = x 64 y1 = y 65 code1 = encode(x, y) 66 else: 67 # print('eee') 68 x2 = x 69 y2 = y 70 code2 = encode(x, y) 71 if area == True: # 若滿足條件即可划線 72 cv2.line(img, (x1, y1), (x2, y2), (0, 255, 255)) # 這里傳遞的點的坐標必須是整型,否則出錯 73 return 74 75 76 # 做測試用的 不用理會 77 def test(): 78 print('test test test!') 79 c = encode(23, 46) 80 print(c) 81 82 83 def main(): # 主函數 84 # 繪制矩形窗口與直線 這里是顯示裁剪之前的樣子 要測試記得把下面的裁剪部分注釋掉 85 cv2.rectangle(img, (300, 150), (500, 350), 255) 86 # cv2.line(img, (0, 0), (260, 260), (0, 255, 255)) 87 # cv2.line(img, (400, 50), (200, 400), (0, 255, 255)) 88 # cv2.line(img, (350, 100), (450, 400), (0, 255, 255)) 89 # cv2.line(img, (150, 250), (650, 250), (0, 255, 255)) 90 # cv2.line(img, (400, 75), (400, 425), (0, 255, 255)) 91 # cv2.line(img, (350, 300), (450, 200), (0, 255, 255)) 92 93 # 窗口裁剪直線 這里是顯示裁剪之后的樣子 94 CohenSutherland(0, 0, 260, 260) # 傳遞直線起點和終點坐標 95 CohenSutherland(400, 50, 200, 400) 96 CohenSutherland(350, 100, 450, 400) 97 CohenSutherland(150, 250, 650, 250) 98 CohenSutherland(400, 75, 400, 425) 99 CohenSutherland(350, 300, 450, 200) 100 # test() 101 102 # 窗口顯示圖形 103 cv2.imwrite('out1.jpg', img) # 生成一張圖片 104 cv2.namedWindow('image', cv2.WINDOW_NORMAL) # 直接顯示窗口 105 cv2.resizeWindow('image', 800, 500) # 定義frame的大小 106 cv2.imshow('image', img) # 顯示圖像 107 k = cv2.waitKey(0) # 等待鍵盤輸入,為毫秒級 0表示一直等待 108 if k == 27: # 鍵盤上Esc鍵的鍵值 按下就會退出 設置好條件更加方便 109 cv2.destroyAllWindows() 110 111 112 # print('this message is from main function') 113 114 115 if __name__ == '__main__': 116 main() 117 # print('now __name__ is %s' % __name__)
五.運行結果
裁剪前:
裁剪后:
五.思考與收獲
學會把思路理清后,自己能夠寫出基本框架的程序,一些不懂的知識就去及時百度,以后要系統學習python的庫,感覺很好用,
在學習的過程中,也要加強做筆記的能力,多寫博客吧。