python 讀取坐標數據畫出最大面積的輪廓


項目要求,現需要一個能根據Excel的坐標數據,在圖像上進行描點連線,並且連線的方式是以所有的點進行最大輪廓連線。現在實現了要求,但是由於代碼寫得太亂,我只是簡單的說一下實現算法就好了,代碼也會貼出來,時間過於久,我也有些地方忘記了,但是整體算法還是記得的~

下面開始簡單的說一下:

首先,所有點的坐標數據就像下圖所示:

 

 

 

 問題:如何將所有的點以最大的輪廓連線呢??

 思路:應該是數學問題,如何將坐標列表重新排序成以最大輪廓的坐標列表,因為matplotlib庫可以根據一個列表里面的坐標數據直接生成連線。

我的排序算法是:

1.首先,將所有坐標進行排序,可以以x排序,然后找到最左邊的坐標點和最右邊的坐標;

2.以最左邊和最右邊的坐標進行求解方程,兩點確定一條直線,就是求該直線的方程;

3.將剩余的所有坐標x代入步驟2的方程組,求出解和坐標y進行比較,將線下方的點和上方的點坐標分別求出來,然后存入一個列表備份;

4.將下方坐標的列表進行排序,由小到大,然后存入一個最終列表中,最終列表第一個肯定是最左邊的點,然后就是下方的點;

5.將下方坐標的列表進行排序,由大到小,然后繼續分別存入最終列表,最后在最終列表中在加上最左邊的坐標點,使連線閉合;

6.然后用matplotlib里面的pyplot函數,將最終列表連線即可。

上面的算法我寫在了一個函數里面,這是非常不對的,但是如今還是不想將其整理出來,哈哈,思維不亂就行~~

  1         try:
  2             # 先提取成一個個位置坐標
  3             coordinate = []
  4             for i in range(len(x)):
  5                 coordinate.append([x[i], y[i]])
  6 
  7             # print(coordinate)
  8 
  9             # 這是基准列表,x最小最大,y最小最大
 10             sort_list = []
 11             # 剩下的坐標數據
 12             ret_list = []
 13             # 下方的點數據
 14             under_list = []
 15             # 總的排序結果
 16             final_list = []
 17             # 臨時列表
 18             temp = []
 19 
 20             # 下方的點
 21             down_dot = []
 22             # 上方的點
 23             up_dot = []
 24 
 25             y_max_and_y_min = []
 26 
 27             # 進行x排序
 28             sort_x(coordinate)
 29 
 30             # 排序完成肯定是第一個最小,最后一個最大,將這兩個數據添加到確定的基准列表里面
 31             sort_list.append(coordinate[0])
 32             sort_list.append(coordinate[len(coordinate) - 1])
 33 
 34             # 這下面進行以y大小進行排序,,重新存儲在一個新列表里面
 35             sort_y(coordinate)
 36             y_max_and_y_min.append(coordinate[0])
 37             y_max_and_y_min.append(coordinate[len(coordinate) - 1])
 38 
 39             # 這句代碼實現的功能是和基准列表進行比對,求除了基准列表剩下的所有坐標數據
 40             ret_list = [item for item in coordinate if item not in sort_list] + [item for item in sort_list if
 41                                                                                  item not in coordinate]
 42 
 43             print("確定的坐標:" + str(sort_list))
 44 
 45             print("剩余的坐標: " + str(ret_list))
 46 
 47             # 最左坐標
 48             left_x = sort_list[0][0]
 49             left_y = sort_list[0][1]
 50 
 51             # 最右坐標
 52             right_x = sort_list[1][0]
 53             right_y = sort_list[1][1]
 54 
 55             # 最下坐標
 56             down_x = y_max_and_y_min[0][0]
 57             down_y = y_max_and_y_min[0][1]
 58 
 59             # 最上坐標
 60             up_x = y_max_and_y_min[1][0]
 61             up_y = y_max_and_y_min[1][1]
 62 
 63             # 實現兩點之間的公式
 64             # y = k*x + b
 65 
 66             # 總判斷公式,,蠻重要
 67             k = (right_y - left_y) / (right_x - left_x)
 68             b = left_y - k * left_x
 69 
 70             print("y=" + str(k) + "x" + '+' + str(b))
 71 
 72             # 開始進行比對,判斷剩余列表里面的每一個點,如果在直線下方,就加入下方列表里面
 73             for i in range(len(ret_list)):
 74                 # print(ret_list[i])
 75                 if (under(k, b, ret_list[i])):
 76                     under_list.append(ret_list[i])
 77 
 78             print("下面列表的數據", under_list)
 79 
 80             # 對下方列表再以x為基准進行排序
 81             under_list = sort_x(under_list)
 82 
 83             # 排序完成直接都添加到確定的列表里面,先添加一個最左的坐標,在循環結束之后再添加最右的數據
 84             final_list.append(sort_list[0])
 85 
 86             for t in under_list:
 87                 final_list.append(t)
 88                 # 邊添加還邊讓數據從剩余列表里面去掉
 89                 ret_list.remove(t)
 90 
 91             final_list.append(sort_list[1])
 92 
 93             ################################################################################
 94             # 到此,,下方的排序已經結束
 95             print(final_list)
 96             num_under = len(final_list)
 97 
 98             print(ret_list)
 99 
100             # 剩下的列表進行冒泡排序,還是由小到大,但是最后翻轉一下列表就可以
101             ret_list = sort_x(ret_list)
102             ret_list = (list(reversed(ret_list)))
103 
104             print(ret_list)
105 
106             for t in ret_list:
107                 """將剩下的坐標添加到處理后的列表里面"""
108                 final_list.append(t)
109 
110             # 這個是再補一個坐標,使曲線閉合
111             final_list.append(sort_list[0])
112 
113             print(ret_list)
114             print("最終列表-----------", final_list)
115 
116             # 分離后的x,y坐標數據
117             final_x = []
118             final_y = []
119 
120             for i in range(len(final_list)):
121                 """將坐標數據從新分離成兩個列表"""
122                 final_x.append(final_list[i][0])
123                 final_y.append(final_list[i][1])
124 
125             # print(final_x)
126             # print(final_y)
127 
128             # 在這需要將列表翻裝一下,調試好久才發現
129             final_list = list(reversed(final_list))
130 
131             # 將圖像顯示出來
132             # showResult(final_x, final_y,'title', 'x', 'y')
View Code

連線起來的最終效果圖:

 

項目要求2: 判斷一個點是否在所圍的輪廓內。

實現方法:

1.首先判斷是否在x坐標是否在最左,最右之間,y坐標是否在最上,最下坐標之間,如果不在,直接判定不在;

2.判斷是否為原來數據的點,如果是直接判定在輪廓內;

3.然后將需要判斷的坐標代入最左最右組成的方程上,判斷該坐標是該直線的上方還是下方。

4.若在下方,判斷在下方的坐標點哪兩個坐標之間,根據左右兩個坐標點進行直線方程的求解,然后將需判斷坐標的x代入,求解是否大於y坐標,如果大於就判定是在輪廓里面;

5.若在上方,判定條件改成小於才在輪廓里面;

 

代碼如下:

# 下面進行判斷一個點是否在圈內
            # x_judge = 0.396
            # y_judge = 0.592

            x_get = self.input_x.text()
            y_get = self.input_y.text()

            if (len(x_get)==0):
                QMessageBox.critical(self, 'reslult', '請輸入x,y')
                x_judge = final_x[0]
                y_judge = final_y[0]
                judge = [float(x_judge), float(y_judge)]
                self.input_x.setText(str(x_judge))
                self.input_y.setText(str(y_judge))
            else:
                x_judge = float(x_get)
                y_judge = float(y_get)

                judge = [float(x_judge), float(y_judge)]

            if judge == sort_list[0] or judge == sort_list[1] or judge == y_max_and_y_min[0] or judge == \
                    y_max_and_y_min[1]:
                """先判斷是否是基准點"""
                print("在--相等")
                flag=True
                QMessageBox.critical(self,'reslult' , 'in')
            elif is_midle(judge[0], left_x, right_x) and is_midle(judge[1], down_y, up_y):
                """先判斷是否在大圈之內"""
                # 先判斷是在上方的點還是上方的點,如果在下方用下方的公式,否則,相反
                if not under(k, b, judge):
                    print("在下方")
                    for i in range(len(down_dot) - 1):
                        if is_midle(judge[0], down_dot[i][0], down_dot[i + 1][0]):
                            # print(down_dot[i][0],down_dot[i+1][0])
                            print(down_dot[i], down_dot[i + 1])
                            k_test, b_test = generate_equation(down_dot[i], down_dot[i + 1])
                            print(k_test, b_test)
                            if not (under(k_test, b_test, judge)):
                                print("不在")
                                flag = False
                                QMessageBox.critical(self,'reslult' , 'not in')
                                break
                            else:
                                print("")
                                flag = True
                                QMessageBox.critical(self, 'reslult' ,'in')
                                break
                        else:
                            pass
                elif not up_under(k, b, judge):
                    print("在上方")
                    for i in range(len(up_dot) - 1):
                        if is_midle(judge[0], up_dot[i + 1][0], up_dot[i][0]):
                            print(up_dot[i], up_dot[i + 1])
                            k_test, b_test = generate_equation(up_dot[i], up_dot[i + 1])
                            print(k_test, b_test)
                            if (up_under(k_test, b_test, judge)):
                                print("")
                                flag = True
                                QMessageBox.critical(self, 'reslult' ,'in')
                                break
                            else:
                                print("不在")
                                flag=False
                                QMessageBox.critical(self,'reslult' , 'not in')
                                break
                        else:
                            pass

            else:
                print("不在")
                flag = False
                QMessageBox.critical(self,'reslult' ,'not in')


            if (flag == True):
                plt.scatter(x_judge, y_judge, color='green', marker='o')
            elif (flag == False):
                plt.scatter(x_judge,y_judge,color='red',marker='o')

            plt.plot(final_x, final_y, color='black', linewidth=2.0)
            plt.scatter(final_x, final_y, color='black', marker='+')
            plt.title(str(flag))
            plt.xlabel('x')
            plt.ylabel('y')
            for x1, y1 in zip(final_x, final_y):
                plt.text(x1,y1, str(x1), ha='center', va='bottom', fontsize=10.5)
            for x2, y2 in zip(final_x, final_y):
                plt.text(x2+0.1,y2, str(y2), ha='center', va='bottom', fontsize=10.5)


            plt.show()
View Code

 

至此,項目的要求算為完成,然后組成了GUI界面,所用的庫是PYQT5。其實這個庫真的挺好用的。

 

 

 

說下打包成exe 的時候遇到的問題,最新版的matplotlib庫用pyinstaller根據打包不成功,如果按照網上的說法一個個依賴去尋找,太過於麻煩,

我查了半天資料,發現有個大佬說舊版的matplotlib可以,我連忙卸載新版的,下載舊版的,打包,,成功。就很完美~~~

至此,項目結束。

 

完成代碼我放在了我的網盤上,有點點亂~下面是網盤鏈接:

https://wws.lanzous.com/i7xTKiz7o7g

 

 


免責聲明!

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



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