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

 
原文地址:https://www.cnblogs.com/Jay12138/p/14073072.html