• 2021-04-18 08:19:47

Quick search for local extremes

The new function extr.m analyses the given real vector carrying a sequence of samples to be analyzed. At the end, it returns a cell array of extreme positions in the sequence. The cell array consists of two cells only. The first one contains the logical vector of maxima and the other the similar one of minima. Should more equal values be present in adjacent elements of the vector, only one position is returned. The attention is also paid on low memory requirements and a speed of the procedure.

Forms of calls:

L = extr(x); % Find true local extremes

% ..... x vector containing a sequence to be analyzed,

% ..... L cell array {L(1), L(2)}, where

% ..... L(1) is logical vector of positions of maxima,

% ..... L(2) is logical vector of positions of minima.

There are also circumstances, when the processing time is critical for a user, while the exact true extrems are of less priority. In that case he may use:

L = extr(c,0); % Find true and false local extrems.

False extrems form pairs of equal value minimum-maximum laying somewhere on the trend of the sequence. They are not extrems, but they do not harm in certain cases of consecutive processing.

Examples:

demoXtr; % See the program and figure demoXtr.jpg

L = extr(x);

y = x(L(1)|L(2)); % y is a vector of all extremes

clear, x=rand(1e7,1)-.5; tic, L=extr(x); toc

Elapsed time is 2.974584 seconds. % (3GHz PC, Windows XP Prof.)

clear, x=rand(1e7,1)-.5; tic, L=extr(x,0); toc

Elapsed time is 1.392926 seconds. % (3GHz PC, Windows XP Prof.)

Hopefully, the function is error-free. If not, please, let me know.

更多相关内容
• 这是一个非常快速和简单的局部极值查找器。 它同时计算局部最大值和最小值，并将索引返回到输入向量中的相应值（通过返回第一个点的索引来处理常量区域）。 这不是 Matlab 的 findpeaks 函数的替代品，后者功能更...
• 在课堂上，我们介绍了许多边缘感知过滤：双边，WLS，局部极值，扩散图，域变换，局部拉普拉斯算子，L0最小化和引导滤波器。 在此作业中，您有三个选择。 对于第一个选项，您必须实现“本地极值”或“扩散图”（未...
• 返回具有局部极值（最小值、最大值）位置和值的结构。 输出结构要素： minx：最小位置miny：最小值maxx：最大位置maxy：最大值 例子： v=[1 3 5 5 2 -2 -2 -1 8 -10 5]; o1=极值(v) o2=extrems(v,'ysort') o3=...
• % 找到真正的局部极值 % ..... x 包含待分析序列的向量， % ..... L 元胞数组 {L(1), L(2)}，其中% ..... L(1) 是最大值位置的逻辑向量， % ..... L(2) 是最小值位置的逻辑向量。 在某些情况下，处理时间对用户来说...
• 遗传算法是基于达尔文进化论和孟德尔遗传学而发展形成，它是处理非线性模型参数估计的一类通用性较强的寻优方法。遗传算法寻求最优解的基本思想是：从代表问题的可能潜在解集的一个种群出发，此种群由基因编码的一定...
• 为求得类似仿真函数的黑箱函数优化问题的全部局部极值点，提出了一种基于适应值曲面分析的新算法。首先，对适应值距离相关系数(fitness distance correlation, FDC)进行了改进，探讨了改进FDC指标与适应值曲面崎岖度...
• robot容易陷入局部极小值：当所受引力与斥力的合立场在某一点有局部极值时，在局部极小值点周围的各个位置的合力场梯度都指向局部极小值，导致robot在局部极小值点周围振荡，无法自行走出该区域。
• 利用python求图像的局部极值，并标注。这是http://www.imagepy.org/的作者原创，我只是对其理解之后改进和说明，欢迎大家使用这个小软件！
• 本文提出了一种新颖的局部极值动态系统，该系统中的每个玩家只需要识别邻居的收益，并在邻居获得最低收益时随机改变其策略即可。 在此更新规则下，针对不同大小的邻域（以其相应的半径r为特征），探讨了合作的演变...
• % 约束点可以限制为局部极值。 % [pfunc,pval]=polyfitcon(x,y,n,xc,yc,p0,isLocExt) 返回％pfunc，存储用于拟合的阶数'n'的多项式。 % pval，拟合多项式的权重。 ％pfunc = @（x，pval）pval（1）。* x。^（n-1）+...
• Persistence1D是用于在一维数据中查找局部极值及其持久性的类。 局部最小值和局部最大值根据它们的持久性被提取、配对和排序。 代码在 O(n log n) 时间内运行，其中 n 是输入点的数量。 请检查doc文件夹以获取详细的...
• 它是完全矢量化的，而且速度非常快。 设计用于 EMD/HHT 算法。
• 局部平坦/极值未定义 可选变量 'hood' 指定像素的拓扑结构用于寻找极值的邻域，选项为 hood = 4 或 hood = 8， 8 是默认值。 某些极值可能无法在单个点上进行数学定义，即鞍点下方的示例是像素双峰——这是一个...
• 快速搜索局部极值以获得最大信息系数（MIC）
• 局部极值提取算法 这是http://www.imagepy.org/的作者原创，我只是对其理解之后改进和说明，欢迎大家使用这个小软件！ 有需要C++的朋友，可有留邮箱，经测试和改进的版本！ 算法原理：（按照程序思路来，...

局部极值提取算法

这是http://www.imagepy.org/的作者原创，我只是对其理解之后改进和说明，欢迎大家使用这个小软件！

有需要C++的朋友，可有留邮箱，经测试和改进的版本！

算法原理：（按照程序思路来，当然其中很多可以改进的地方）

第一步：

先进行距离变换（这类问题都是要通过几何操作进行，距离变换就是几何距离）

第二步：

先找全局可能最大值，然后对图像进行标记

全局可能最大值是基础，3X3核在图像上滑动去找全局可能最大值。标记是为了掩膜操作更方便，你看opencv很多函数都有掩膜，PS上面也有那个白色的膜。

　　　　　　  图片结果是：背景和最大值标记3，前景标记1，图像边界标记0（为了防止越界）　　　　　　  貌似下面的图片显示有问题，matploylib的显示有时候确实有问题，Debug的时候就和显示不一样，没关系这一步比较简单。

第三步：

对全局可能最大值进行排除，这一步是程序核心！这里以求最大值为例，最小值相反。

• 　　首先对找到的最大值进行排序--从大到小
• 　　按照从大到小的顺序去寻找每个最大值的领地
• 　　领地按照“目标范围”和“目标深度”两个原则，具体表现形式为：“不重合”、“不包括”、“领主大于等于领地”

下面以图说明两个大原则：

目标范围：

下图A1这个最大最他所占领的范围由用户输入，假设半径为y，则 x1 = x2 = y ，x1和x2的范围就是A1的范围，P点虽然很低，但是不属于A1的范围，所以不去占领。

目标深度：

下图A1的深度也又用户输入，假设输入为y，则 y1 = y，高度确定之后，那么P点虽然也在山脊上，但是不会被A1所占领。

下面以图为例进一步说明三个具体形式：

注释：三个具体形式是建立在两个原则之上的，所以理解上面是结局算法的基础。

不重合形式：

下图A1和A2有领土纠纷，但是A1峰值高所以先进行领地划分，当A2进行领地划分的时候一旦接触A1的领地就立马被消灭，最后只剩A1的存在。

不包括形式：

下图A1先进行领土划分，过程中直接把A2消灭了，不存在A2的领土划分

领主大于等于领地形式，也可以叫同等峰值先来先得形式：

由于A1先进行领土划分，所以后面的都被消灭了，读到这里你会发现这个程序的BUG，后面再详细谈论这一点

目标深度原则

要确定和你预定的深度是不是符合，比如你想要山峰之间的深度都是在10cm以上，那么有些不符合的就得去除，去除原则肯定矮的GG

注释：大佬的程序没有几何距离，还有部分Bug，部分经过修正了。

程序有待改进：

这部分可以通过处理---“同样的峰值且山脉相连”的一类极值点，对其平均、覆盖范围最多等操作取一个中间的值！

由于python用的不熟练，而且现在时间太晚了脑子转不动，以后用C++写的时候再改进这一点。

2017.10.17更新：

1.对上面第二步：可能最大值进行补充

请看下面这个图，中间位置肯定不是最大值区域，而且通过上面的第三步过滤也是没办法过滤的，具体看上面原理就知道了，所以需要在第二步进行过滤！

本程序利用如下方法：

A.每一层的最大值都大于外面一层，sum[0]>=sum[1] && sum[1]>sum[2] && sum[2]>sum[3]，这里使用到9X9的内核

B.记录每一层最大值出现的位置X0和X1，然后最大值的距离(abs(x0.x - x1.x) <= 2 && abs(x0.y - x1.y) <= 2)小于等于2，这里不严谨，因为每层最大值不止一个。

C.记录最大值出现的数量n_count >= 3

 1 　　　　　　　float sum[4] = { 0 };//存储最大值进行对比、在这里说不清楚看博客2017.10.17更新
2             sum[0] = img[3][j];
3             Point x0 = Point(0, 0);
4             Point x1 = Point(0, 0);
5             uchar n_count = 0;
6             for (int m = 2; m < 5; m++)
7             {
8                 for (int n = -1; n < 2; n++)
9                 {
10                     if (m == 3 && n == 0) continue;
11                     sum[1] = sum[1] < img[m][j + n] ? img[m][j + n] : sum[1];
12                     x0 = sum[0] == img[m][j + n] ? Point(m, n) : x0;
13                     n_count = sum[0] == img[m][j + n] ? n_count+1 : n_count;
14                     //flag = img[3][j + 0] < img[m][j + n] ? true : flag;//如果目标像素小于周围任何一个像素就说明这个一定不是最大值
15                 }
16             }
17             for (int m = 1; m < 6; m++)
18             {
19                 for (int n = -2; n < 3; n++)
20                 {
21                     if (2 <= m && m <= 4 && -1 <= n && n <= 1) continue;
22                     sum[2] = sum[2] < img[m][j + n] ? img[m][j + n] : sum[2];
23                     x1 = sum[0] == img[m][j + n] ? Point(m, n) : x1;
24                     n_count = sum[0] == img[m][j + n] ? n_count+1 : n_count;
25                     //flag = img[3][j + 0] < img[m][j + n] ? true : flag;//如果目标像素小于周围任何一个像素就说明这个一定不是最大值
26                 }
27             }
28             for (int m = 0; m < 7; m++)
29             {
30                 for (int n = -3; n < 4; n++)
31                 {
32                     sum[3] = sum[3] < img[m][j + n] && !(1 <= m && m <= 5 && -2 <=n && n <= 2) ? img[m][j + n] : sum[3];
33                     //flag = img[3][j+0] < img[m][j + n] ? true : flag;//如果目标像素小于周围任何一个像素就说明这个一定不是最大值
34                 }
35             }
36             x1 = (x1.x == 0 && x1.y == 0) || n_count >= 3 ? x0 : x1;//判断是否存在5X5的最大值（和目标点相同）
37             int tmp = sum[0] >= sum[1] && sum[1] >= sum[2] && sum[2] >= sum[3] && (abs(x0.x - x1.x) <= 2 && abs(x0.y - x1.y) <= 2)
38                 ? 0 : FillBlock(src, mask_tmp, Point(j, i));//tmp没意义，就是为了调用后面的函数而已
39         }

2.对第三步进行补充

A.搜索过程遇到边界，那就把这个最大值点去除if (img[i][fill_point[count].x + j] == 2 || msk[i][fill_point[count].x + j] == 0) max_point[k].data = 1;

3.效果图

注释：满足一个条件就判定为最大值！

  1 import scipy.ndimage as ndimg
2 import numpy as np
3 from numba import jit
4 import cv2
5
6 def neighbors(shape):
7     dim = len(shape)
8     block = np.ones([3] * dim)
9     block[tuple([1] * dim)] = 0
10     idx = np.where(block > 0)
11     idx = np.array(idx, dtype=np.uint8).T
12     idx = np.array(idx - [1] * dim)
13     acc = np.cumprod((1,) + shape[::-1][:-1])
14     return np.dot(idx, acc[::-1])
15
16
17 @jit  # trans index to r, c...
18
19 def idx2rc(idx, acc):
20     rst = np.zeros((len(idx), len(acc)), dtype=np.int16)
21     for i in range(len(idx)):
22         for j in range(len(acc)):
23             rst[i, j] = idx[i] // acc[j]
24             idx[i] -= rst[i, j] * acc[j]
25     return rst
26
27
28 #@jit  # fill a node (may be two or more points)
29
30 def fill(img, msk, p, nbs, buf):
31     msk[p] = 3
32     buf[0] = p
33     back = img[p]
34     cur = 0
35     s = 1
36     while cur < s:
37         p = buf[cur]
38         for dp in nbs:
39             cp = p + dp
40             if img[cp] == back and msk[cp] == 1:
41                 msk[cp] = 3
42                 buf[s] = cp
43                 s += 1
44                 if s == len(buf):
45                     buf[:s - cur] = buf[cur:]
46                     s -= cur
47                     cur = 0
48         cur += 1
49     #msk[p] = 3
50
51
52 #@jit  # my mark
53
54 def mark(img, msk, buf, mode):  # mark the array use (0, 1, 2)
55     omark = msk
56     nbs = neighbors(img.shape)
57     idx = np.zeros(1024 * 128, dtype=np.int64)
58     img = img.ravel()  # 降维
59     msk = msk.ravel()  # 降维
60     s = 0
61     for p in range(len(img)):
62         if msk[p] != 1: continue
63         flag = False
64         for dp in nbs:
65             if mode and img[p + dp] > img[p]:
66                 flag = True
67                 break
68             elif not mode and img[p + dp] < img[p]:
69                 flag = True
70                 break
71
72         if flag : continue
73         else    : fill(img, msk, p, nbs, buf)
74         idx[s] = p
75         s += 1
76         if s == len(idx): break
77     plt.imshow(omark, cmap='gray')
78     return idx[:s].copy()
79
80
81
82 def filter(img, msk, idx, bur, tor, mode):
83     omark = msk
84     nbs = neighbors(img.shape)
85     acc = np.cumprod((1,) + img.shape[::-1][:-1])[::-1]
86     img = img.ravel()
87     msk = msk.ravel()
88
89     arg = np.argsort(img[idx])[::-1 if mode else 1]
90
91     for i in arg:
92         if msk[idx[i]] != 3:
93             idx[i] = 0
94             continue
95         cur = 0
96         s = 1
97         bur[0] = idx[i]
98         while cur < s:
99             p = bur[cur]
100             if msk[p] == 2:
101                 idx[i] = 0
102                 break
103
104             for dp in nbs:
105                 cp = p + dp
106                 if msk[cp] == 0 or cp == idx[i] or msk[cp] == 4: continue
107                 if mode and img[cp] < img[idx[i]] - tor: continue
108                 if not mode and img[cp] > img[idx[i]] + tor: continue
109                 bur[s] = cp
110                 s += 1
111                 if s == 1024 * 128:
112                     cut = cur // 2
113                     msk[bur[:cut]] = 2
114                     bur[:s - cut] = bur[cut:]
115                     cur -= cut
116                     s -= cut
117
118                 if msk[cp] != 2: msk[cp] = 4
119             cur += 1
120         msk[bur[:s]] = 2
121         #plt.imshow(omark, cmap='gray')
122
123     return idx2rc(idx[idx > 0], acc)
124
125
126 def find_maximum(img, tor, mode=True):
127     msk = np.zeros_like(img, dtype=np.uint8)
128     msk[tuple([slice(1, -1)] * img.ndim)] = 1
129     buf = np.zeros(1024 * 128, dtype=np.int64)
130     omark = msk
131     idx = mark(img, msk, buf, mode)
132     plt.imshow(msk, cmap='gray')
133     idx = filter(img, msk, idx, buf, tor, mode)
134     return idx
135
136
137 if __name__ == '__main__':
139     from scipy.ndimage import gaussian_filter
140     from time import time
141     import matplotlib.pyplot as plt
142
144     img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
145     ret2, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
146     img[:] = ndimg.distance_transform_edt(img)
147     plt.imshow(img, cmap='gray')
148     pts = find_maximum(img, 20, True)
149     start = time()
150     pts = find_maximum(img, 10, True)
151     print(time() - start)
152     plt.imshow(img, cmap='gray')
153     plt.plot(pts[:, 1], pts[:, 0], 'y.')
154     plt.show()

C++版本

老版本、不稳定，可以看思路

  1 //---fill black value
2 int FillBlock(Mat src, Mat &mask, Point center)
3 {
4     uchar back = src.at<uchar>(center.y, center.x);
5     vector<Point> fill_point;
6     int count = 0, count_mount = 1;
7     fill_point.push_back(center);
8     while (count < count_mount)
9     {
10         vector<uchar*> img;
11         vector<uchar*> msk;
12         for (int i = -1; i < 2; i++)
13         {
14             img.push_back(src.ptr<uchar>(fill_point[count].y + i));
16         }
17         for (size_t i = 0; i < 3; i++)
18         {
19             for (int j = -1; j < 2; j++)
20             {
21                 if (img[i][fill_point[count].x + j] == back && !(j == 0 && i == 1) && msk[i][fill_point[count].x + j] == 255)
22                 {
23                     fill_point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1));
24                     msk[i][fill_point[count].x + j] = 1;
25                 }
26             }
27         }
28         msk[1][fill_point[count].x] = 1;
29         count_mount = fill_point.size() - 1;
30         fill_point.erase(fill_point.begin());
31     }
32     return 0;
33 }
35 //---@_src
38 {
39     Mat src = _src.getMat(),mask_tmp = Mat::zeros(src.size(), CV_8UC1);
41     Mat rows = Mat::zeros(Size(src.cols, 1), CV_8UC1), cols = Mat::zeros(Size(1, src.rows), CV_8UC1);
43     Mat src_rows_end = mask_tmp.row(src.rows - 1);
45     Mat src_cols_end = mask_tmp.col(src.cols - 1);
46     rows.copyTo(src_rows_beg); rows.copyTo(src_rows_end);
47     cols.copyTo(src_cols_beg); cols.copyTo(src_cols_end);
48     for (size_t i = 1; i < src.rows-1; i++)
49     {
50         uchar *img0 = src.ptr<uchar>(i - 1);
51         uchar *img  = src.ptr<uchar>(i);
52         uchar *img1 = src.ptr<uchar>(i + 1);
54         for (size_t j = 1; j < src.cols-1; j++)
55         {
56             bool flag = false;
57             //msk[j] = img[j] == 0 ? 0 : msk[j];
58             if (msk[j] != 255) continue;
59             flag = (img[j] < img[j - 1] || img[j] < img[j + 1]
60                 || img[j] < img0[j] || img[j] < img0[j - 1]
61                 || img[j] < img0[j + 1] || img[j] < img1[j]
62                 || img[j] < img1[j - 1] || img[j] < img1[j + 1])
63                 ? true : false;
64             int tmp = flag == true ? FillBlock(src, mask_tmp, Point(j, i)) : 0;
65         }
66     }
68 }
69 //---filter parts max value
70 //---@
71 //---@
72 //---@gap
74
76 {
77     Mat src = _src.getMat();
78
79     typedef struct MyStruct
80     {
81         Point position;
82         float data;
83     }MyStruct;
84
86     vector<MyStruct> max_point;
87     for (size_t i = 0; i < src.rows; i++)
88     {
89         uchar *img = src.ptr<uchar>(i);
91         for (size_t j = 0; j < src.cols; j++)
92         {
93             if (msk[j] != 255) continue;
94             MyStruct my_struct;
95             my_struct.data = img[j];
96             my_struct.position = Point(j, i);
97             max_point.push_back(my_struct);
98         }
99     }
100     for (size_t i = 0; i < max_point.size(); i++)
101     {
102         for (size_t j = i; j < max_point.size(); j++)
103         {
104             MyStruct temp;
105             if (max_point[i].data <= max_point[j].data)
106             {
107                 if (max_point[j].data == 0) continue;
108                 temp = max_point[j];
109                 max_point[j] = max_point[i];
110                 max_point[i] = temp;
111             }
112         }
113     }
114     //---find max
115     for (size_t k = 0; k < max_point.size(); k++)//---
116     {
117         uchar back = src.at<uchar>(max_point[k].position.y, max_point[k].position.x);
118         vector<Point> fill_point;
119         int count = 0, count_mount = 1;
120         fill_point.push_back(max_point[k].position);
121
122         while (count < count_mount &&  max_point[k].data != 1)
123         {
124             vector<uchar*> img;
125             vector<uchar*> msk;
126             for (int i = -1; i < 2; i++)
127             {
128                 img.push_back(src.ptr<uchar>(fill_point[count].y + i));
130             }
131             for (int i = 0; i < 3; i++)
132             {
133                 for (int j = -1; j < 2; j++)
134                 {
135                     //---
136                     uchar x = pow((max_point[k].position.x - fill_point[count].x + j), 2); //(max_point[k].position.x - img[i][fill_point[count].x + j])*(max_point[k].position.x - img[i][fill_point[count].x + j]);
137                     uchar y = pow((max_point[k].position.y - (fill_point[count].y + i - 1)) , 2); // (max_point[k].position.y - img[i][fill_point[count].y + j])*(max_point[k].position.y - img[i][fill_point[count].x + j]);
138                     uchar distance = sqrt(x + y);
139                     if (img[i][fill_point[count].x + j] <= img[1][fill_point[count].x] - gap
140                         || msk[i][fill_point[count].x + j] == 3
141                         || msk[i][fill_point[count].x + j] == 0
142                         || (j == 0 && i == 1)
143                         || distance >= radius) continue;
144                     if (img[i][fill_point[count].x + j] == 2) max_point[k].data = 1;
145                     msk[i][fill_point[count].x + j] = 3;
146                     fill_point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1));
147                     count_mount++;
148                 }
149             }
150             count++;
151         }
152         if (max_point[k].data == 1)
153         {
154             for (size_t i = 0; i < fill_point.size(); i++)
155             {
157             }
158         }
159         else
160         {
161             for (size_t i = 0; i < fill_point.size(); i++)
162             {
164             }
165             max_point[k].data = 255;
167         }
168     }
169 }
View Code

C++版本：

2017.10.17更新

  1 int FillBlock(Mat src, Mat &mask, Point center)
2 {
3     uchar back = src.at<uchar>(center.y, center.x);
4     vector<Point> fill_point;
5     int count = 0, count_mount = 1;
6     fill_point.push_back(center);
7     while (count < count_mount)
8     {
9         vector<uchar*> img;
10         vector<uchar*> msk;
11         for (int i = -1; i < 2; i++)
12         {
13             img.push_back(src.ptr<uchar>(fill_point[count].y + i));
15         }
16         for (size_t i = 0; i < 3; i++)
17         {
18             for (int j = -1; j < 2; j++)
19             {
20                 if (img[i][fill_point[count].x + j] == back && !(j == 0 && i == 1) && msk[i][fill_point[count].x + j] == 255)
21                 {
22                     fill_point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1));
23                     msk[i][fill_point[count].x + j] = 1;
24                 }
25             }
26         }
27         msk[1][fill_point[count].x] = 1;
28         count_mount = fill_point.size() - 1;
29         fill_point.erase(fill_point.begin());
30     }
31     return 0;
32 }
33
35 {
36     Mat src = _src.getMat(),mask_tmp = Mat::zeros(src.size(), CV_8UC1);
38     Mat rows = Mat::zeros(Size(src.cols, 1), CV_8UC1), cols = Mat::zeros(Size(1, src.rows), CV_8UC1);
40     Mat src_rows_end = mask_tmp.row(src.rows - 1);
42     Mat src_cols_end = mask_tmp.col(src.cols - 1);
43     rows.copyTo(src_rows_beg); rows.copyTo(src_rows_end);
44     cols.copyTo(src_cols_beg); cols.copyTo(src_cols_end);
45
46     for (size_t i = 3; i < src.rows-3; i++)
47     {
48         vector<uchar*> img;
50         uchar* img1 = src.ptr(i);
51         for (int k = -3; k < 4; k++)
52         {
53             img.push_back(src.ptr<uchar>(k + i));
54         }
55         for (size_t j = 3; j < src.cols-3; j++)
56         {
57             bool flag = false;
58             if (msk[j] != 255) continue;
59             float sum[4] = { 0 };
60             sum[0] = img[3][j];
61             Point x0 = Point(0, 0);
62             Point x1 = Point(0, 0);
63             uchar n_count = 0;
64             for (int m = 2; m < 5; m++)
65             {
66                 for (int n = -1; n < 2; n++)
67                 {
68                     if (m == 3 && n == 0) continue;
69                     sum[1] = sum[1] < img[m][j + n] ? img[m][j + n] : sum[1];
70                     x0 = sum[0] == img[m][j + n] ? Point(m, n) : x0;
71                     n_count = sum[0] == img[m][j + n] ? n_count+1 : n_count;
72                     //flag = img[3][j + 0] < img[m][j + n] ? true : flag;//如果目标像素小于周围任何一个像素就说明这个一定不是最大值
73                 }
74             }
75             for (int m = 1; m < 6; m++)
76             {
77                 for (int n = -2; n < 3; n++)
78                 {
79                     if (2 <= m && m <= 4 && -1 <= n && n <= 1) continue;
80                     sum[2] = sum[2] < img[m][j + n] ? img[m][j + n] : sum[2];
81                     x1 = sum[0] == img[m][j + n] ? Point(m, n) : x1;
82                     n_count = sum[0] == img[m][j + n] ? n_count+1 : n_count;
83                     //flag = img[3][j + 0] < img[m][j + n] ? true : flag;//如果目标像素小于周围任何一个像素就说明这个一定不是最大值
84                 }
85             }
86             for (int m = 0; m < 7; m++)
87             {
88                 for (int n = -3; n < 4; n++)
89                 {
90                     sum[3] = sum[3] < img[m][j + n] && !(1 <= m && m <= 5 && -2 <=n && n <= 2) ? img[m][j + n] : sum[3];
91                     //flag = img[3][j+0] < img[m][j + n] ? true : flag;
92                 }
93             }
94             x1 = (x1.x == 0 && x1.y == 0) || n_count >= 3 ? x0 : x1;
95             int tmp = sum[0] >= sum[1] && sum[1] >= sum[2] && sum[2] >= sum[3] && (abs(x0.x - x1.x) <= 2 && abs(x0.y - x1.y) <= 2)
96                 ? 0 : FillBlock(src, mask_tmp, Point(j, i));
97         }
98     }
100 }
101
103 {
104     Mat src = _src.getMat();
105
106     typedef struct MyStruct
107     {
108         Point position;
109         float data;
110     }MyStruct;
111
113     vector<MyStruct> max_point;
114     for (size_t i = 0; i < src.rows; i++)
115     {
116         uchar *img = src.ptr<uchar>(i);
118         for (size_t j = 0; j < src.cols; j++)
119         {
120             if (msk[j] != 255) continue;
121             MyStruct my_struct;
122             my_struct.data = img[j];
123             my_struct.position = Point(j, i);
124             max_point.push_back(my_struct);
125         }
126     }
127     for (size_t i = 0; i < max_point.size(); i++)
128     {
129         for (size_t j = i; j < max_point.size(); j++)
130         {
131             MyStruct temp;
132             if (max_point[i].data <= max_point[j].data)
133             {
134                 if (max_point[j].data == 0) continue;
135                 temp = max_point[j];
136                 max_point[j] = max_point[i];
137                 max_point[i] = temp;
138             }
139         }
140     }
141
142     for (size_t k = 0; k < max_point.size(); k++)//---
143     {
144         uchar back = src.at<uchar>(max_point[k].position.y, max_point[k].position.x);
145         vector<Point> fill_point;
146         int count = 0, count_mount = 1;
147         fill_point.push_back(max_point[k].position);
148
149         while (count < count_mount &&  max_point[k].data != 1)
150         {
151             vector<uchar*> img;
152             vector<uchar*> msk;
153             for (int i = -1; i < 2; i++)
154             {
155                 img.push_back(src.ptr<uchar>(fill_point[count].y + i));
157             }
158             for (int i = 0; i < 3; i++)
159             {
160                 for (int j = -1; j < 2; j++)
161                 {
162                     //---
163                     double x = pow((max_point[k].position.x - fill_point[count].x + j), 2); //(max_point[k].position.x - img[i][fill_point[count].x + j])*(max_point[k].position.x - img[i][fill_point[count].x + j]);
164                     double y = pow((max_point[k].position.y - (fill_point[count].y + i - 1)), 2); // (max_point[k].position.y - img[i][fill_point[count].y + j])*(max_point[k].position.y - img[i][fill_point[count].x + j]);
165                     int distance = sqrt(x + y);
166                     if (img[i][fill_point[count].x + j] <= img[0][fill_point[count].x] - gap
167                         || msk[i][fill_point[count].x + j] == 3
168                         //|| msk[i][fill_point[count].x + j] == 0
169                         || (j == 0 && i == 1)
170                         || distance >= radius) continue;
171                     if (img[i][fill_point[count].x + j] == 2 || msk[i][fill_point[count].x + j] == 0) max_point[k].data = 1;
172                     msk[i][fill_point[count].x + j] = 3;
173                     fill_point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1));
174                     count_mount++;
175                 }
176             }
177             count++;
178         }
179         if (max_point[k].data == 1)
180         {
181             for (size_t i = 0; i < fill_point.size(); i++)
182             {
184             }
185         }
186         else
187         {
188             for (size_t i = 0; i < fill_point.size(); i++)
189             {
191             }
192             max_point[k].data = 255;
194         }
195     }
196     vector<Point> print_wjy;
197     for (size_t i = 0; i < mask.rows; i++)
198     {
200         for (size_t j = 0; j < mask.cols; j++)
201         {
202             if (msk[j] == 255)
203                 print_wjy.push_back(Point(j, i));
204         }
205
206     }
207     return print_wjy;
208 }

转载于:https://www.cnblogs.com/wjy-lulu/p/7416135.html

展开全文
• 真的结束于最优点吗？...我们知道，在局部最优点附近，各个维度的导数都接近0，而我们训练模型最常用的梯度下降法又是基于导数与步长的乘积去更新模型参数的，因此一旦陷入了局部最优点，...

真的结束于最优点吗？

我们知道，在局部最优点附近，各个维度的导数都接近0，而我们训练模型最常用的梯度下降法又是基于导数与步长的乘积去更新模型参数的，因此一旦陷入了局部最优点，就像掉进了一口井，你是无法直着跳出去的，你只有连续不间断的依托四周的井壁努力向上爬才有可能爬出去。更何况梯度下降法的每一步对梯度正确的估计都在试图让你坠入井底，因此势必要对梯度“估计错很多次”才可能侥幸逃出去。那么从数学上看，什么才是局部最优点呢？

这个问题看似很白痴，很多人会说“局部最优点不就是在loss曲面上某个一阶导数为0的点嘛”。这就不准确啦，比如下面这个马鞍形状的中间的那个点：

（图片来自《deep learning》）

显然这个点也是（一阶）导数为0，但是肯定不是最优点。事实上，这个点就是我们常说的鞍点

显然，只用一阶导数是难以区分最优点和鞍点的。

我们想一下，最优点和鞍点的区别不就在于其在各个维度是否都是最低点嘛～只要某个一阶导数为0的点在某个维度上是最高点而不是最低点，那它就是鞍点。而区分最高点和最低点当然就是用二阶导数（斜率从负变正的过程当然就是“下凸”，即斜率的导数大于0，即二阶导数大于0。反之则为“上凹”，二阶导数小于0）。

也就是说，若某个一阶导数为0的点在至少一个方向上的二阶导数小于0，那它就是鞍点。在鞍点处，横着看的话，鞍点就是个极小值点，但是竖着看的话，鞍点就是极大值点（线性代数和最优化算法过关的同学应该能反应过来，鞍点处的Hessian矩阵的特征值有正有负

二阶泰勒展开式

当Hessian矩阵正定时（即对任意的u≠0，有u⊤∇2f（x）u > 0恒成立），对于任何方向向量u，通过二阶泰勒展开式，可知x必定是一个局部最小值点。同样，当Hessian矩阵负定时，此点是一个局部最大值点；当Hessian矩阵同时具有正负特征值时，此点便是鞍点

那么二阶导数大于0和小于0的概率各是多少呢？由于我们并没有先验知识，因此按照最大熵原理，我们认为二阶导数大于和小于0的概率均为0.5！

那么对于一个有n个参数的机器学习/深度学习模型，“loss曲面”即位于n+1维空间（loss值为纵轴，n个参数为n个横轴）。在这个空间里，如果我们通过梯度下降法一路下滑终于滑到了一个各方向导数均为0的点，那么它为局部最优点的概率即0.5^n，为鞍点的概率为1-0.5^n，显然，当模型参数稍微一多，即n稍微一大，就会发现这个点为鞍点的概率会远大于局部最优点！

所以实际中，当我们的深度学习模型收敛时，几乎没有必要认为它收敛到了一个局部最优点，这完全等同于杞人忧天也就是说，如果最后模型确实在梯度下降法的指引下收敛到了一个导数为0的点，那这个点几乎可以肯定就是一个鞍点。

显然，站在马鞍中央的时候，虽然很难翻过两边的山坡，但是往前或者往后随便走一步就能摔下马鞍！我们默认使用的mini-batch梯度下降法本身就是带有噪声的梯度估计，哪怕我们位于梯度为0的点，也经常在某个mini-batch下的估计把它估计偏了，导致往前或者往后挪了一步摔下马鞍，也就是mini-batch的梯度下降法使得模型很容易逃离特征空间中的鞍点。

原因如下：

样本均值的方差

首先，我们假设每个样本相对于大自然真实分布的标准差为σ，那么根据概率统计的知识，很容易推出n个样本的标准差为σ/sqrt(n)（如上推导），从这里可以看出，我们使用样本来估计梯度的时候，1个样本带来σ的标准差，但是使用n个样本区估计梯度并不能让标准差线性降低（也就是并不能让误差降低为原来的1/n，即无法达到σ/n），而n个样本的计算量却是线性的（每个样本都要平等的跑一遍前向算法）。

因此想一想，当样本量少的时候会带来很大的方差，而这个大方差恰好会导致我们在梯度下降到很差的局部最优点（只是微微凸下去的最优点）和鞍点的时候不稳定，一不小心就因为一个大噪声的到来导致炸出了局部最优点，或者炸下了马（此处请保持纯洁的心态！），从而有机会去寻找更优的最优点。但是与之相反的，当样本量很多时，方差很小（咦？最开始的时候好像在说标准差来着，反正方差与标准差就差个根号，没影响的哈~），对梯度的估计要准确和稳定的多，因此反而在差劲的局部最优点和鞍点时反而容易自信的呆着不走了，从而导致神经网络收敛到很差的点上，跟出了bug一样的差劲。

那么问题来了，既然局部最优点很难踩到，鞍点也很容易逃离出去，那么为什么我们的模型看起来是收敛了呢？

初学者可能会说 “诶诶，会不会是学习率太大了，导致在“鞍点”附近震荡？” 首先，鞍点不像最优点那样容易震荡，而且哪怕你不断的减小学习率继续让模型收敛，你这时计算output层或者后几层的梯度向量的长度时会发现它依然离0很遥远！

所以更令人信服的是，在高维空间里（深度学习问题上）真正可怕的不是局部最优也不是鞍点问题，而是一些特殊地形。比如大面积的平坦区域：

在平坦区域，虽然导数不为0但是却不大。虽然是在不断下降但是路程却非常长。对于优化算法来说，它需要走很多很多步才有可能走过这一片平坦区域。甚至在这段地形的二阶导数过于特殊的情况下，一阶优化算法走无穷多步也走不出去（设想一下，如果终点在一米外，但是你第一次走0.5米，后续每一步都是前一步的一半长度，那么你永远也走不到面前的一米终点处）。

所以相比于栽到最优点和鞍点上，优化算法更有可能载到这种类似平坦区的地形中（如果这个平坦区又是“高原地带”，即loss值很高的地带，那么恭喜你悲剧了）。更糟糕的是，由于高维地形难以可视化，还有很多更复杂的未知地形会导致假收敛，一旦陷入到这些危险地形中，几乎是无解的。

所以说，在深度学习中，与其担忧模型陷入局部最优点怎么跳出来，更不如去好好考虑：

1、如何去设计一个尽量没有“平坦区”等危险地形的loss空间，即着手于loss函数的设计以及深度学习模型的设计

2、尽量让模型的初始化点远离空间中的危险地带，让最优化游戏开始于简单模式，即着手于模型参数的初始化策略

3、让最优化过程更智能一点，该加速冲时加速冲，该大胆跳跃时就大胆跳，该慢慢踱步时慢慢走，对危险地形有一定的判断力，如梯度截断策略；

4、开外挂，本来下一步要走向死亡的，结果被外挂给拽回了安全区，如batch normalization策略等。

针对 batch size，不能设置的太大也不能太小，实际工程中最常用 mini-batch，一般size设置为几十或者几百；另外，听说GPU对2的幂次的batch可以发挥更佳的性能，但是：

因此，对于二阶优化算法，减小 batch size 带来的收敛速度提升远 < 引入大量误差导致的性能下降，因此在使用二阶优化算法时，往往要采用大batch哦。此时往往batch设置成几千甚至一两万才能发挥出最佳性能（比如 batch size 设置的 2048 配合 L-BFGS 取得了比 SGD 好得多的效果，无论是收敛速度还是最终的准确率）。

算法优化之道：避开鞍点-CSDN.NET

训练神经网络时如何确定batch的大小

你的模型真的陷入局部最优点了吗

展开全文
• 本文提出了一种利用不断调大学习率的方法试图跳出SGD优化过程中的局部极小值或者鞍点的方法，并提出了两种具体的方法：随机漫步起跳法和历史最优起跳法，实验证明相对常规优化方法有一定性能提升。

/* 版权声明：可以任意转载，转载时请标明文章原始出处和作者信息 .*/

黄通文   张俊林（ 2016年12月）

注：这篇文章的思路以及本文是我们在2016年底左右做自动发现探索网络结构过程中做的，当时做完发现ICLR 2017有类似论文提出相似的方法，所以没有做更多实验并就把这篇东西搁置了。今天偶然翻到，感觉还是有一定价值，所以现在发出来。

一般深度神经网络由于很深的深度以及非线性函数这两个主要因素，导致目标的损失函数是非凸函数，该损失函数曲面中包含许多的驻点，驻点可能是以下三类关键点中的一种:鞍点，局部极小值，全局极小值，其中全局极小值是我们期望训练算法能够找到的，而其它两类是期望能够避免的。一个示意性的损失函数曲面如下图所示：

不少学习算法在训练过程中，随着误差的减少，迭代次数的增加，步长变化越来越小，训练误差越来越小直到变为零，局部探索到一个驻点，如果这个点是误差曲面的鞍点，即不是最大值也不是最小值的平滑曲面，那么一般结果表现为性能比较差；如果这个驻点是局部极小值，那么表现为性能较好，但不是全局最优值。目前大多数训练算法在碰到无论是鞍点还是局部极值点的时候，因为此刻学习率已经变得非常小，所以会陷入非全局最优值不能自拔。这其实就是目前采用SGD类似的一阶导数方法训练机器学习系统面临的一个很重要的问题。

一．两种跳出驻点的方法

上面说了基本思路，其实思路很朴实也很简单：常见的训练方法在刚开始的时候学习率设置的比较大，这样可以大幅度快步向极值点迈进，加快收敛速度，随着越来越接近极值点，逐步将学习率调小，这样避免步子太大跳过极值点或者造成优化过程震荡结果不稳定。当优化到性能无法再提升的时候，此时大概率陷入了鞍点或者局部极小值，表现为梯度接近于0而且一般此时学习率已经调整到非常小的程度了。跳出驻点的思路就是说：此时可以重新把已经调整的很小的学习率数值放大，强行逼迫优化算法跳出此刻找到的鞍点或者极值点，在上述示意的损失函数曲面上等于当前在某个山谷的谷底（或者某个平台上，即鞍点），此时迈出一大步跳到比较远的地方，然后继续常规的优化过程，就是不断调小学习率，期望找到附近的另外一个山谷谷底，如此往复若干次，然后找出这些谷底哪个谷底更深，然后采取这个最深的谷底对应的参数作为模型参数。

所以这里的关键是在优化进行不下去的时候重新调大学习率跳出当前的山谷，根据起跳点的不同，可以有两种不同的方法：

方法1：随机漫步起跳法

这个方法比较简单，就是说当前优化走到哪个山谷谷底，就从当前位置起跳，直接调大学习率即可，因为这样类似于走到哪里走不下去就从哪里开始跳到附近的远处，走到哪算哪，所以称之为“随机漫步起跳法”。

方法2:历史最优起跳法

上面说过，在这种优化方法过程中，会不断进入某个谷底，那么假设在训练集上优化历史上已经经过K个谷底，在验证集上其对应参数的模型性能是可以知道的，分别为P1，P2……Pk。随机漫步起跳法就是从Pk作为起跳点进行起跳。而历史最优起跳法则从P1,P2……Pk中性能最优的那个山谷谷底开始起跳，假设Pi=Max(P1,P2……Pk)，那么从第i个山谷开始起跳，如果跳出后发现第j个山谷的性能Pj要优于Pi，则后面从Pj的位置开始起跳，当从Pi跳过K次都没有发现比Pi性能更好的山谷，此时可以终止优化算法。这个有点像是Pi性能的“一山望着一山高”，然后不断从历史最高峰跳到更高的高山上，可以保证性能应该越来越好。从道理上讲感觉这种历史最优起跳法要好于随机漫步起跳法，但是实验结果表明两种不同的起跳方法性能是差不多的，有时候这个稍好点，有时候那个稍好点，没有哪个方法确定性的比另外一个好。

二．相关的实验及其结果

为了检验上述跳出驻点的思路是否有效，我们选择了若干深层CNN模型来测试，这里列出其中某个模型的结果，这个模型结构可能看上去有点奇怪，前面说过这个思路是我们去年在做网络最优结构自动探索任务中产生的，所以这两个比较奇怪的结构是从自动生成的网络结构里面随机选出的，性能比较好。分类数据是cifar10图片分类数据，选择带动量的SGD算法作为基准方法来进行相关实验的验证。

2.1模型结构及参数配置

CNN模型结构如下图所示：

其模型结构为：model structure:('init-29', [('conv', [('nb_filter', 16)]), ('conv',[('nb_filter', 256)]), ('maxp', [('pool_size', 2)]), ('conv', [('nb_filter',256)]), ('conv', [('nb_filter', 256)]), ('conv', [('nb_filter', 256)]),('maxp', [('pool_size', 2)]), ('conv', [('nb_filter', 256)])])")

后面部分接上fc(512,relu)+dropout(0.2)+fc(10,softmax)的分类层；

学习算法设置的参数为: 选择使用Nesterov的带动量的随机梯度下降法，初始学习率为0.01，衰减因子为1e-6，momentum因子为0.9。

2.2 Nesterov+动量SGD（固定学习率）实验效果

在上节所述的模型设置下，从结果看，最好的测试精度是0.9060,模型的误差和精度都变化地比较平滑

2.3学习率自适应减少进行训练的实验结果

其它配置类似于2.1.2所述，唯一的不同在于：使用常规策略对学习率进行缩小的改变。改变学习率的策略是如果误差10次不变化，那么学习率缩小为原来的0.1倍。 总迭代次数设置为100次。 训练误差、训练准确率、测试误差、测试准确率的变化曲线为：

从训练结果看，第47次学习率变化，性能上有一次大幅度的提高：

从训练和测试的结果看，测试精度最高的是在第80轮，达到了0.9144。此时的训练误差0.3921，训练准确率0.9926，测试误差0.3957，测试准确率0.9144。

由此可见，增加学习率的动态改变，在学习速度和质量上要比原始的学习率恒定的训练方法要好，这里性能上增加近一个百分点。

2.4随机漫步起跳法实验结果

从上面的两组实验结果过程的最后阶段可以看出，误差和准确率变化较小，很可能优化过程陷入一个局部最优值，可能是一个极值，也可能是一个鞍点，不管怎样称呼它，它就是一个驻点。（从结果看，应该是一个局部最优值）。在其它实验条件与2.1.3节所述相同情况下，采取上文所述的随机漫步起跳法强迫优化算法跳出当前局部最优，即在学习率比较低的时候，进行扩大学习率的方式（直接设置为0.1，后面再常规的逐步减少），让其在误差曲面的区域中去寻找更多的驻点。 具体做法是：如果当前发现经过三次学习率变小没有带来准确率的提升，那么在当前训练的点，将学习率恢复到初始的学习率即0.01。 迭代的效果如下训练误差、训练准确率、测试误差、测试准确率的变化曲线如下图为：

从训练过程看，从当前迭代的当前位置出发，采用学习率缩小和扩大相结合的方式,目前最高能在第153轮的准确率提高到0.9236，比之前最好的0.9144有一点提升，说明这样的学习率变大策略也是一种可行的思路。

另外，从图中看，由于我们变大学习率许多次，每次学习率变大都会呈现一个波动形式，故结果表现出锯齿状的波动趋势。

2.5历史最优起跳法实验结果

我们做了类似的实验，发现历史最优起跳法与随机漫步起跳法性能相当，有时这个好点有时那个好点，没有发现性能明显差异。

我们随机抽了其它几个最优网络结构自动探索出的深度神经网络结构，表现与上述网络结构类似，而如果基础网络结构本身性能越差，这个差别越大。

所以可以得出的结论是：优化过程中采用常规动态学习率调整效果要优于固定学习率的方法，而随机漫步起跳法效果略优于常规的动态学习率调整方法，但是历史最优起跳法相对常规动态学习率方法没有发现改善。

相关文献

1. SGDR: STOCHASTIC GRADIENT DESCENT RESTARTS .ICLR-2017

展开全文
• 本次实验利用了基于局部极值的分水岭算法来实现圆斑点的检测。在OPENCV中提供了simpleBlobDetector特征检测器来实现这种斑点检测算法，正如它的名称，该算法使用最简单的方式来检测斑点类的特征点，效果较好，设置...
• 多层感知机解决了之前无法模拟异或逻辑的缺陷，同时更多的层数也让网络更能够刻画现实世界中的复杂情形。...但是随着神经网络层数的加深，优化函数越来越容易陷入局部最优解（即过拟合，在训练样本上有很好的拟
• nbr = np.zeros(len(vec)+1, dtype=bool) nbr[0] = True nbr[1:-1] = np.greater_equal(vec[1:], vec[:-1]) maxmask = (nbr[:-1] & ~nbr[1:])
• MatLab 函数 fingpeaks 对一维数组求解局部极大和极小值 徐海蛟老师课堂教学 举例说明。 clc; clear;% 清屏清空变量 figure('Color', 'w');% 背景：白色 Data = [1 -2 3 -4 5 -6 7 8 5 4 1 2 -3 -1 -5 9 7 -6 5]; ...
• 从x1x_1x1​出发开始运用梯度下降法，得到局部最小m1m_1m1​ 随机选取x2x_2x2​点作为初始点 从x2x_2x2​出发开始运用梯度下降法，得到局部最小m2m_2m2​ 一直往下继续 最后选到了100个mmm值 选取100个中的最小即可...
• 商品期货历史收盘价核回归、极值识别
• 极值的具体语句：极值：data是你的数据，find(diff(sign(diff(data)))==-2)+1找到极大值的位置find(diff(sign(diff(data)))==2)+1找到极小值的位置data(find(diff(sign(diff(data)))==-2)+1)和data(find(diff(sign...
• 今天小编就为大家分享一篇python 梯度法求解函数极值的实例，具有很好的参考价值，希望对大家有所帮助。一起跟随小编过来看看吧
• 极值的具体语句：极值：data是你的数据，find(diff(sign(diff(data)))==-2)+1找到极大值的位置find(diff(sign(diff(data)))==2)+1找到极小值的位置data(find(diff(sign(diff(data)))==-2)+1)和data(find(diff(sign...
• 利用matlab，自编的二维曲线极值点寻找方法。代码里面对输入输出有详细的描述。
• 对于一个多元函数，用最速下降法（又称梯度下降法）求其极小值的迭代格式为 其中为负梯度方向，即最速下降方向，αkαk为搜索步长。 一般情况下，最优步长αkαk的确定要用到线性搜索技术，比如精确线性搜索，但是...

...