運用python實現Cohen-Sutherland直線段裁剪算法


本篇為原創,僅僅作為學習參考之用,轉載請說明。

一.題目描述:

在二維觀察中,需要在觀察坐標系下根據窗口大小對二維圖形進行裁剪(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__)
View Code

 

五.運行結果

裁剪前:

 

 

裁剪后:

 

 五.思考與收獲

學會把思路理清后,自己能夠寫出基本框架的程序,一些不懂的知識就去及時百度,以后要系統學習python的庫,感覺很好用,

在學習的過程中,也要加強做筆記的能力,多寫博客吧。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM