ms-vite-plugin 1.4.39 → 1.4.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/api/dotocr.md +160 -0
- package/docs/api/opencv.md +1638 -0
- package/docs/apicn/dotocr.md +161 -0
- package/docs/apipython/dotocr.md +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1638 @@
|
|
|
1
|
+
# OpenCV 模块 (cv)
|
|
2
|
+
|
|
3
|
+
提供图像读写、颜色与阈值、滤波、几何变换、绘制、模板/特征匹配、轮廓、形态学、直方图、霍夫、扫码等能力。模块名为 `cv`,无中文别名。
|
|
4
|
+
|
|
5
|
+
注意:
|
|
6
|
+
|
|
7
|
+
- Mat 用字符串句柄表示,形如 `$CV_MAT$_…`。
|
|
8
|
+
- 多数算子返回新句柄;`rectangle` / `circle` / `line` / `putText` / `fillPoly` / `polylines` / `drawContours` / `floodFill` / `ellipse` / `drawMarker` / `arrowedLine` / `fillConvexPoly` / `insertChannel` / `watershed` / `grabCut` 等会就地修改输入 Mat(或 options 中指定的目标句柄)。
|
|
9
|
+
- 与 `image` 可通过 `fromImageId` / `toImageId` 互通(独立拷贝)。
|
|
10
|
+
- 路径 / msbundle / imageId / `screen` 等读图只用 `imread`;其它 API 只接受 Mat 句柄;`imdecode` 只解 base64。
|
|
11
|
+
- 用完请 `release` / `releaseAll`(同时存活句柄上限约 32)。
|
|
12
|
+
- 颜色参数为 **BGR**;也可用 `#RRGGBB`。
|
|
13
|
+
|
|
14
|
+
## 功能一览
|
|
15
|
+
|
|
16
|
+
| 类别 | API |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| 读图 / 截屏 | `capture` · `imread` · `imdecode` · `imwrite` · `imencode` · `fromImageId` / `toImageId` |
|
|
19
|
+
| Mat | `Mat` / `zeros` / `ones` · `clone` · `empty` / `isRelease` · `release` / `releaseAll` · `getSize` / `at` / `set` · `copyTo` |
|
|
20
|
+
| 颜色 / 阈值 | `cvtColor` · `threshold` · `adaptiveThreshold` · `inRange` · `CLAHE` / `equalizeHist` · `applyColorMap` · `decolor` |
|
|
21
|
+
| 算术 / 位运算 | `add` / `subtract` / `multiply` / `divide` · bitwise_* · `absdiff` · `addWeighted` · `convertScaleAbs` · `normalize` / `norm` · `meanStdDev` · `findNonZero` · `countNonZero` · `minMaxLoc` / `mean` / `sum` · `split` / `merge` · `hconcat` / `vconcat` · `LUT` · `compare` · `min` / `max` · `extractChannel` / `insertChannel` · `mixChannels` · `pow` / `sqrt` / `exp` / `log` · `magnitude` · `cartToPolar` / `polarToCart` · `PSNR` · `scaleAdd` |
|
|
22
|
+
| 滤波边缘 | `GaussianBlur` / `blur` / `medianBlur` / `bilateralFilter` / `boxFilter` / `stackBlur` · `Canny` / `Sobel` / `Laplacian` / `Scharr` · `filter2D` / `sepFilter2D` · `pyrDown` / `pyrUp` · `edgePreservingFilter` · `detailEnhance` · `pencilSketch` · `stylization` · `fastNlMeansDenoising` / `fastNlMeansDenoisingColored` · `pyrMeanShiftFiltering` |
|
|
23
|
+
| 几何 | `resize` / `crop` / `rotate` / `flip` · `copyMakeBorder` · `warpAffine` / `warpPerspective` / `warpPolar` · `remap` · `getRotationMatrix2D` · `getAffineTransform` · `getPerspectiveTransform` · `invertAffineTransform` · `findHomography` · `perspectiveTransform` · `estimateAffine2D` / `estimateAffinePartial2D` · `getRectSubPix` · `phaseCorrelate` |
|
|
24
|
+
| 绘制 | `rectangle` / `circle` / `line` / `ellipse` / `arrowedLine` / `drawMarker` · `putText` / `fillPoly` / `fillConvexPoly` / `polylines` / `drawContours` · `getTextSize` |
|
|
25
|
+
| 匹配 | `matchTemplate` / `matchTemplateLoc` · `SIFT` / `ORB` / `AKAZE` / `BRISK` / `KAZE` / `FAST` / `AGAST` / `MSER` / `SimpleBlobDetector` · `BFMatcher` / `knnMatch` · `FlannBasedMatcher` / `flannKnnMatch` · `drawKeypoints` / `drawMatches` |
|
|
26
|
+
| 轮廓 | `findContours` · `boundingRect` / `minAreaRect` / `boxPoints` · `contourArea` / `arcLength` / `approxPolyDP` / `convexHull` / `convexityDefects` / `isContourConvex` · `moments` / `HuMoments` / `matchShapes` · `pointPolygonTest` · `fitEllipse` / `fitLine` / `minEnclosingCircle` |
|
|
27
|
+
| 霍夫 / 连通域 / 分割 | `HoughLines` / `HoughLinesP` / `HoughCircles` / `LSD` · `connectedComponents` / `connectedComponentsWithStats` · `distanceTransform` · `floodFill` · `goodFeaturesToTrack` / `cornerHarris` / `cornerSubPix` / `cornerMinEigenVal` / `preCornerDetect` · `spatialGradient` · `watershed` / `grabCut` · `integral` |
|
|
28
|
+
| 直方图 | `calcHist` · `compareHist` · `calcBackProject` |
|
|
29
|
+
| Photo / 克隆 | `inpaint` · `seamlessClone` · `colorChange` · `illuminationChange` · `textureFlattening` |
|
|
30
|
+
| 扫码 / 检测 | `detectQRCode` · `detectBarcode` · `encodeQRCode` · `CascadeClassifier` · `HOGDetect` |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 快速示例
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const src = cv.capture();
|
|
38
|
+
const gray = cv.cvtColor(src, { code: cv.COLOR_BGR2GRAY });
|
|
39
|
+
const edges = cv.Canny(gray, { threshold1: 100, threshold2: 200 });
|
|
40
|
+
const feat = cv.SIFT(gray, { nfeatures: 500 });
|
|
41
|
+
logi(`keypoints=${feat.keypoints.length}`);
|
|
42
|
+
cv.imwrite(`${file.getInternalDir("documents")}/edges.png`, edges);
|
|
43
|
+
cv.release(src);
|
|
44
|
+
cv.release(gray);
|
|
45
|
+
cv.release(edges);
|
|
46
|
+
cv.release(feat.descriptors);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
与 `image` 模块衔接:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const imageId = image.captureScreen();
|
|
53
|
+
const mat = cv.imread(imageId); // 或 cv.fromImageId(imageId)
|
|
54
|
+
image.release(imageId);
|
|
55
|
+
const gray = cv.cvtColor(mat, { code: cv.COLOR_BGR2GRAY });
|
|
56
|
+
const outId = cv.toImageId(gray);
|
|
57
|
+
cv.release(mat);
|
|
58
|
+
cv.release(gray);
|
|
59
|
+
image.saveTo(outId, `${file.getInternalDir("documents")}/gray.jpg`);
|
|
60
|
+
image.release(outId);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 句柄与生命周期
|
|
66
|
+
|
|
67
|
+
### capture - 截屏为 Mat
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
function capture(
|
|
71
|
+
x?: number,
|
|
72
|
+
y?: number,
|
|
73
|
+
ex?: number,
|
|
74
|
+
ey?: number,
|
|
75
|
+
): Mat | null;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**参数:**
|
|
79
|
+
|
|
80
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
81
|
+
| --- | --- | --- | --- | --- |
|
|
82
|
+
| `x` | number | 否 | 0 | 区域左上角 X 坐标 |
|
|
83
|
+
| `y` | number | 否 | 0 | 区域左上角 Y 坐标 |
|
|
84
|
+
| `ex` | number | 否 | 0 | 区域右下角 X 坐标 |
|
|
85
|
+
| `ey` | number | 否 | 0 | 区域右下角 Y 坐标 |
|
|
86
|
+
|
|
87
|
+
无参或全 0 表示全屏。
|
|
88
|
+
|
|
89
|
+
**返回值:**
|
|
90
|
+
|
|
91
|
+
| 类型 | 描述 |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| `string` | Mat 句柄,失败返回 `null` |
|
|
94
|
+
|
|
95
|
+
**示例:**
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const full = cv.capture();
|
|
99
|
+
const roi = cv.capture(100, 100, 300, 300);
|
|
100
|
+
cv.release(full);
|
|
101
|
+
cv.release(roi);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### imread - 读取图片为 Mat(唯一路径类入口)
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
function imread(path: string): Mat | null;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**参数:**
|
|
111
|
+
|
|
112
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
113
|
+
| --- | --- | --- | --- | --- |
|
|
114
|
+
| `path` | string | 是 | - | 见下方支持的输入源 |
|
|
115
|
+
|
|
116
|
+
**支持的输入源:**
|
|
117
|
+
|
|
118
|
+
| 输入 | 说明 |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| msbundle/res 相对路径 | 如 `"template.png"`、`"images/logo.jpg"` |
|
|
121
|
+
| 手机绝对路径 | 如 documents 下文件 |
|
|
122
|
+
| `$MS_IMG$_…` | `image` 模块 imageId |
|
|
123
|
+
| `"screen"` | 当前屏幕截图 |
|
|
124
|
+
| `"shortcut"` | HID 快捷指令截图 |
|
|
125
|
+
| `"actionScreenshot"` | HID 系统截图 |
|
|
126
|
+
| `"vpnScreenshot"` | VPN/iDevice 截图 |
|
|
127
|
+
| `http://` / `https://` | 网络图片 |
|
|
128
|
+
| `media:n` | 相册第 n 张(从 1 起) |
|
|
129
|
+
| `data:image/...;base64,...` | data URI |
|
|
130
|
+
|
|
131
|
+
**返回值:**
|
|
132
|
+
|
|
133
|
+
| 类型 | 描述 |
|
|
134
|
+
| --- | --- |
|
|
135
|
+
| `string` | Mat 句柄,失败返回 `null` |
|
|
136
|
+
|
|
137
|
+
**示例:**
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const a = cv.imread("template.png");
|
|
141
|
+
const dir = file.getInternalDir("documents");
|
|
142
|
+
const b = cv.imread(`${dir}/shot.jpg`);
|
|
143
|
+
const imageId = image.captureScreen();
|
|
144
|
+
const c = cv.imread(imageId);
|
|
145
|
+
image.release(imageId);
|
|
146
|
+
cv.release(a);
|
|
147
|
+
cv.release(b);
|
|
148
|
+
cv.release(c);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### imdecode - 解码 base64 为 Mat
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
function imdecode(data: string): Mat | null;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**参数:**
|
|
158
|
+
|
|
159
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
160
|
+
| --- | --- | --- | --- | --- |
|
|
161
|
+
| `data` | string | 是 | - | 纯 base64,或 `data:image/...;base64,...` |
|
|
162
|
+
|
|
163
|
+
**说明:** 不解析文件路径 / msbundle / imageId;路径类请用 `imread`。常与 `imencode` 成对使用。
|
|
164
|
+
|
|
165
|
+
**返回值:** Mat 句柄;失败 `null`。
|
|
166
|
+
|
|
167
|
+
**示例:**
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
const m = cv.imread("template.png");
|
|
171
|
+
const b64 = cv.imencode(".png", m);
|
|
172
|
+
const again = cv.imdecode(b64);
|
|
173
|
+
cv.release(m);
|
|
174
|
+
cv.release(again);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### imwrite - 保存 Mat 到本地文件
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
function imwrite(path: string, mat: Mat): boolean;
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**参数:**
|
|
184
|
+
|
|
185
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
186
|
+
| --- | --- | --- | --- | --- |
|
|
187
|
+
| `path` | string | 是 | - | 本地绝对路径(写入磁盘,不是 msbundle) |
|
|
188
|
+
| `mat` | Mat | 是 | - | Mat 句柄 |
|
|
189
|
+
|
|
190
|
+
**返回值:** 成功 `true`,失败 `false`。
|
|
191
|
+
|
|
192
|
+
**示例:**
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
const src = cv.capture();
|
|
196
|
+
cv.imwrite(`${file.getInternalDir("documents")}/out.png`, src);
|
|
197
|
+
cv.release(src);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### imencode - 编码 Mat 为 base64
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
function imencode(ext: string, mat: Mat, quality?: number): string | null;
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**参数:**
|
|
207
|
+
|
|
208
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
209
|
+
| --- | --- | --- | --- | --- |
|
|
210
|
+
| `ext` | string | 是 | - | 如 `.png` / `.jpg` / `png` |
|
|
211
|
+
| `mat` | Mat | 是 | - | Mat 句柄 |
|
|
212
|
+
| `quality` | number | 否 | 90 | JPEG 质量(仅 jpg 有效) |
|
|
213
|
+
|
|
214
|
+
**返回值:** 纯 base64 字符串(无 data URI 前缀);失败 `null`。
|
|
215
|
+
|
|
216
|
+
**示例:**
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const b64 = cv.imencode(".jpg", mat, { quality: 85 });
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### fromImageId / toImageId - 与 image 互通
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
function fromImageId(imageId: string): Mat | null;
|
|
226
|
+
function toImageId(mat: Mat): string | null;
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**参数:**
|
|
230
|
+
|
|
231
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
232
|
+
| --- | --- | --- | --- | --- |
|
|
233
|
+
| `imageId` | string | 是 | - | `image` 模块句柄 |
|
|
234
|
+
| `mat` | Mat | 是 | - | `cv` Mat 句柄 |
|
|
235
|
+
|
|
236
|
+
**说明:** 均为独立拷贝。`fromImageId(id)` 与 `imread(id)` 对 imageId 效果相同。
|
|
237
|
+
|
|
238
|
+
**示例:**
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const imageId = image.captureScreen();
|
|
242
|
+
const mat = cv.fromImageId(imageId);
|
|
243
|
+
image.release(imageId);
|
|
244
|
+
const outId = cv.toImageId(mat);
|
|
245
|
+
cv.release(mat);
|
|
246
|
+
image.release(outId);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Mat / zeros / ones - 创建矩阵
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
function Mat(options: { rows: number; cols: number; type?: number; scalar?: number[] }): Mat | null;
|
|
253
|
+
function zeros(options: { rows: number; cols: number; type?: number }): Mat | null;
|
|
254
|
+
function ones(options: { rows: number; cols: number; type?: number }): Mat | null;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**参数:**
|
|
258
|
+
|
|
259
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
260
|
+
| --- | --- | --- | --- | --- |
|
|
261
|
+
| `rows` / `cols` | number | 是 | - | 行 / 列 |
|
|
262
|
+
| `type` | number | 否 | `CV_8UC3` | 如 `cv.CV_8UC1` |
|
|
263
|
+
| `scalar` | number[] | 否 | - | 仅 `Mat`:填充值 |
|
|
264
|
+
|
|
265
|
+
**示例:**
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
const z = cv.zeros({ rows: 100, cols: 100, type: cv.CV_8UC3 });
|
|
269
|
+
const filled = cv.Mat({ rows: 10, cols: 10, type: cv.CV_8UC1, scalar: [255] });
|
|
270
|
+
cv.release(z);
|
|
271
|
+
cv.release(filled);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### clone / empty / isRelease / release / releaseAll
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
function clone(mat: Mat): Mat | null;
|
|
278
|
+
function empty(mat: Mat): boolean;
|
|
279
|
+
function isRelease(mat: Mat): boolean;
|
|
280
|
+
function release(mat: Mat): void;
|
|
281
|
+
function releaseAll(): void;
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**说明:**
|
|
285
|
+
|
|
286
|
+
- `clone` 返回新句柄。
|
|
287
|
+
- `empty`:无效句柄或空 Mat 为 `true`。
|
|
288
|
+
- `isRelease`:句柄已释放为 `true`。
|
|
289
|
+
- `releaseAll`:释放当前全部 Mat 句柄。
|
|
290
|
+
|
|
291
|
+
**示例:**
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
const a = cv.capture();
|
|
295
|
+
const b = cv.clone(a);
|
|
296
|
+
cv.release(a);
|
|
297
|
+
logi(cv.isRelease(a)); // true
|
|
298
|
+
cv.release(b);
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### getSize / at / set / copyTo
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
function getSize(mat: Mat): MatInfo | null;
|
|
305
|
+
logi(`${info.width}x${info.height} ch=${info.channels}`);
|
|
306
|
+
cv.set(mat, { row: 10, col: 10, value: [0, 0, 255] });
|
|
307
|
+
const px = cv.at(mat, { row: 10, col: 10 });
|
|
308
|
+
const copy = cv.copyTo(mat);
|
|
309
|
+
cv.release(copy);
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 颜色 / 运算
|
|
315
|
+
|
|
316
|
+
### cvtColor - 颜色空间转换
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
function cvtColor(mat: Mat, code: number): Mat | null;
|
|
320
|
+
const hsv = cv.cvtColor(src, { code: cv.COLOR_BGR2HSV });
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### threshold - 固定阈值
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
function threshold(mat: Mat, options: { thresh?: number; maxval?: number; type?: number }): Mat | null;
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**参数:**
|
|
330
|
+
|
|
331
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
332
|
+
| --- | --- | --- | --- | --- |
|
|
333
|
+
| `thresh` | number | 否 | 127 | 阈值 |
|
|
334
|
+
| `maxval` | number | 否 | 255 | 最大值 |
|
|
335
|
+
| `type` | number | 否 | `THRESH_BINARY` | 如 `THRESH_BINARY` / `THRESH_OTSU` |
|
|
336
|
+
|
|
337
|
+
**示例:**
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
const bin = cv.threshold(gray, { thresh: 127, maxval: 255, type: cv.THRESH_BINARY });
|
|
341
|
+
const otsu = cv.threshold(gray, { type: cv.THRESH_BINARY | cv.THRESH_OTSU });
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### adaptiveThreshold - 自适应阈值
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
function adaptiveThreshold(mat: Mat, options: {
|
|
348
|
+
maxValue?: number;
|
|
349
|
+
adaptiveMethod?: number;
|
|
350
|
+
thresholdType?: number;
|
|
351
|
+
blockSize?: number;
|
|
352
|
+
C?: number;
|
|
353
|
+
}): Mat | null;
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**参数:**
|
|
357
|
+
|
|
358
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
359
|
+
| --- | --- | --- | --- | --- |
|
|
360
|
+
| `maxValue` | number | 否 | 255 | 最大值 |
|
|
361
|
+
| `adaptiveMethod` | number | 否 | `ADAPTIVE_THRESH_GAUSSIAN_C` | 或 `ADAPTIVE_THRESH_MEAN_C` |
|
|
362
|
+
| `thresholdType` | number | 否 | `THRESH_BINARY` | |
|
|
363
|
+
| `blockSize` | number | 否 | 11 | 奇数邻域 |
|
|
364
|
+
| `C` | number | 否 | 2 | 常数偏移 |
|
|
365
|
+
|
|
366
|
+
**示例:**
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
const bin = cv.adaptiveThreshold(gray, {
|
|
370
|
+
maxValue: 255,
|
|
371
|
+
adaptiveMethod: cv.ADAPTIVE_THRESH_GAUSSIAN_C,
|
|
372
|
+
thresholdType: cv.THRESH_BINARY,
|
|
373
|
+
blockSize: 11,
|
|
374
|
+
C: 2,
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### inRange - 范围掩膜
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
function inRange(mat: Mat, options: { lowerb: number[]; upperb: number[] }): Mat | null;
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**参数:** `lowerb` / `upperb` 为各通道下/上限数组。
|
|
385
|
+
|
|
386
|
+
**示例:**
|
|
387
|
+
|
|
388
|
+
```javascript
|
|
389
|
+
const hsv = cv.cvtColor(src, { code: cv.COLOR_BGR2HSV });
|
|
390
|
+
const mask = cv.inRange(hsv, { lower: [0, 80, 80], upper: [20, 255, 255] });
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### bitwise_and / bitwise_or / bitwise_xor / bitwise_not
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
const inv = cv.bitwise_not(mask);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### absdiff / addWeighted / convertScaleAbs
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
const abs = cv.convertScaleAbs(sobel, { alpha: 1, beta: 0 });
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### countNonZero / minMaxLoc / mean / split / merge
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
function countNonZero(mat: Mat): number;
|
|
409
|
+
const mm = cv.minMaxLoc(gray);
|
|
410
|
+
logi(`max=${mm.maxVal} at (${mm.maxLoc.x},${mm.maxLoc.y})`);
|
|
411
|
+
const chans = cv.split(src);
|
|
412
|
+
const merged = cv.merge(chans);
|
|
413
|
+
chans.forEach((c) => cv.release(c));
|
|
414
|
+
cv.release(merged);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## 滤波 / 边缘
|
|
420
|
+
|
|
421
|
+
### GaussianBlur / blur / medianBlur / bilateralFilter / boxFilter
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
function GaussianBlur(mat: Mat, options: { ksize: number | [number, number] | Size; sigmaX?: number; sigmaY?: number }): Mat | null;
|
|
425
|
+
function blur(mat: Mat, options: { ksize: number | [number, number] | Size }): Mat | null;
|
|
426
|
+
function medianBlur(mat: Mat, options: { ksize: number }): Mat | null;
|
|
427
|
+
function bilateralFilter(mat: Mat, options: { d?: number; sigmaColor?: number; sigmaSpace?: number }): Mat | null;
|
|
428
|
+
function boxFilter(mat: Mat, options: { ksize: number | [number, number] | Size; ddepth?: number }): Mat | null;
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
`ksize` 可为 `5`、`[5,5]` 或 `{ width, height }`。高斯核尺寸需为奇数。
|
|
432
|
+
|
|
433
|
+
**示例:**
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
const g = cv.GaussianBlur(src, { ksize: 5, sigmaX: 1.5 });
|
|
437
|
+
const m = cv.medianBlur(src, { ksize: 5 });
|
|
438
|
+
const b = cv.bilateralFilter(src, { d: 9, sigmaColor: 75, sigmaSpace: 75 });
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Canny / Sobel / Laplacian / Scharr / equalizeHist / CLAHE
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
function Canny(mat: Mat, options: { threshold1?: number; threshold2?: number; apertureSize?: number; L2gradient?: boolean }): Mat | null;
|
|
445
|
+
function Sobel(mat: Mat, options: { ddepth?: number; dx?: number; dy?: number; ksize?: number; scale?: number; delta?: number }): Mat | null;
|
|
446
|
+
function Laplacian(mat: Mat, options: { ddepth?: number; ksize?: number; scale?: number; delta?: number }): Mat | null;
|
|
447
|
+
function Scharr(mat: Mat, options: { ddepth?: number; dx?: number; dy?: number; scale?: number; delta?: number }): Mat | null;
|
|
448
|
+
function equalizeHist(mat: Mat): Mat | null;
|
|
449
|
+
function CLAHE(mat: Mat, options?: { clipLimit?: number; tileGridSize?: number | [number, number] | Size }): Mat | null;
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Canny 参数:**
|
|
453
|
+
|
|
454
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
455
|
+
| --- | --- | --- | --- | --- |
|
|
456
|
+
| `threshold1` | number | 否 | 100 | 低阈值 |
|
|
457
|
+
| `threshold2` | number | 否 | 200 | 高阈值 |
|
|
458
|
+
| `apertureSize` | number | 否 | 3 | Sobel 孔径 |
|
|
459
|
+
| `L2gradient` | boolean | 否 | false | 是否用 L2 范数 |
|
|
460
|
+
|
|
461
|
+
**CLAHE 参数:** `clipLimit` 默认 40;`tileGridSize` 默认 `[8,8]`。输入一般为单通道灰度。
|
|
462
|
+
|
|
463
|
+
**示例:**
|
|
464
|
+
|
|
465
|
+
```javascript
|
|
466
|
+
const edges = cv.Canny(gray, { threshold1: 50, threshold2: 150 });
|
|
467
|
+
const sx = cv.Sobel(gray, { dx: 1, dy: 0, ksize: 3 });
|
|
468
|
+
const eq = cv.CLAHE(gray, { clipLimit: 2.0, tileGridSize: [8, 8] });
|
|
469
|
+
const histEq = cv.equalizeHist(gray);
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### pyrDown / pyrUp - 金字塔采样
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
function pyrDown(mat: Mat): Mat | null;
|
|
476
|
+
function pyrUp(mat: Mat): Mat | null;
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
约缩小 / 放大一倍。大图特征匹配前可先 `pyrDown` 降采样。
|
|
480
|
+
|
|
481
|
+
**示例:**
|
|
482
|
+
|
|
483
|
+
```javascript
|
|
484
|
+
const small = cv.pyrDown(src);
|
|
485
|
+
const back = cv.pyrUp(small);
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 几何 / 绘制
|
|
491
|
+
|
|
492
|
+
### resize - 缩放
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
function resize(mat: Mat, options: {
|
|
496
|
+
width?: number;
|
|
497
|
+
height?: number;
|
|
498
|
+
fx?: number;
|
|
499
|
+
fy?: number;
|
|
500
|
+
interpolation?: number;
|
|
501
|
+
}): Mat | null;
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
用 `width`/`height` 指定目标尺寸;也可设为 0 并用 `fx`/`fy` 按比例缩放。`interpolation` 如 `cv.INTER_LINEAR`、`cv.INTER_AREA`。
|
|
505
|
+
|
|
506
|
+
**示例:**
|
|
507
|
+
|
|
508
|
+
```javascript
|
|
509
|
+
const small = cv.resize(src, { width: 360, height: 640 });
|
|
510
|
+
const half = cv.resize(src, { fx: 0.5, fy: 0.5, interpolation: cv.INTER_AREA });
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### crop - 裁剪 ROI(拷贝)
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
function crop(mat: Mat, options: {
|
|
517
|
+
x?: number; y?: number;
|
|
518
|
+
ex?: number; ey?: number;
|
|
519
|
+
}): Mat | null;
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
参数与 `cv.capture` / `image.captureScreen` 一致,使用左上角与右下角。
|
|
523
|
+
|
|
524
|
+
参数为 `{ x, y, ex, ey }`。
|
|
525
|
+
|
|
526
|
+
**示例:**
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
const roi = cv.crop(src, { x: 10, y: 10, ex: 110, ey: 110 });
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### rotate / flip / copyMakeBorder
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
function rotate(mat: Mat, rotateCode: number): Mat | null;
|
|
536
|
+
const f = cv.flip(src, 1);
|
|
537
|
+
const padded = cv.copyMakeBorder(src, {
|
|
538
|
+
top: 10, bottom: 10, left: 10, right: 10,
|
|
539
|
+
borderType: cv.BORDER_CONSTANT, value: [0, 0, 0],
|
|
540
|
+
});
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### getRotationMatrix2D / warpAffine / warpPerspective
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
function getRotationMatrix2D(options: { center: Point | [number, number]; angle?: number; scale?: number }): Mat | null;
|
|
547
|
+
function warpAffine(mat: Mat, options: { M: Mat; width?: number; height?: number; flags?: number }): Mat | null;
|
|
548
|
+
function warpPerspective(mat: Mat, options: { M: Mat; width?: number; height?: number; flags?: number }): Mat | null;
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**示例:**
|
|
552
|
+
|
|
553
|
+
```javascript
|
|
554
|
+
const M = cv.getRotationMatrix2D({ center: { x: 100, y: 100 }, angle: 30, scale: 1 });
|
|
555
|
+
const out = cv.warpAffine(src, { M, width: 200, height: 200 });
|
|
556
|
+
cv.release(M);
|
|
557
|
+
cv.release(out);
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### rectangle / circle / line / putText - 就地绘制
|
|
561
|
+
|
|
562
|
+
就地修改并返回**同一句柄**。`color` 为 BGR 数组或 `#RRGGBB`。
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
function rectangle(mat: Mat, options: RectangleOptions): Mat | null;
|
|
566
|
+
function circle(mat: Mat, options: CircleOptions): Mat | null;
|
|
567
|
+
function line(mat: Mat, options: LineOptions): Mat | null;
|
|
568
|
+
function putText(mat: Mat, options: PutTextOptions): Mat | null;
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**rectangle 参数:** `pt1`+`pt2`,或 `rect`;以及 `color`、`thickness`。
|
|
572
|
+
|
|
573
|
+
**示例:**
|
|
574
|
+
|
|
575
|
+
```javascript
|
|
576
|
+
cv.rectangle(src, {
|
|
577
|
+
pt1: { x: 10, y: 10 },
|
|
578
|
+
pt2: { x: 100, y: 80 },
|
|
579
|
+
color: [0, 0, 255],
|
|
580
|
+
thickness: 2,
|
|
581
|
+
});
|
|
582
|
+
cv.circle(src, { center: { x: 50, y: 50 }, radius: 20, color: "#00FF00", thickness: -1 });
|
|
583
|
+
cv.line(src, { pt1: { x: 0, y: 0 }, pt2: { x: 100, y: 100 }, color: [255, 0, 0], thickness: 2 });
|
|
584
|
+
cv.putText(src, {
|
|
585
|
+
text: "hello",
|
|
586
|
+
org: { x: 20, y: 40 },
|
|
587
|
+
fontFace: cv.FONT_HERSHEY_SIMPLEX,
|
|
588
|
+
fontScale: 1,
|
|
589
|
+
color: [255, 255, 255],
|
|
590
|
+
thickness: 2,
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### fillPoly / polylines / drawContours
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
function fillPoly(mat: Mat, options: { pts: Point[][] | Point[]; color?: number[] | string }): Mat | null;
|
|
598
|
+
function polylines(mat: Mat, options: { pts: Point[][] | Point[]; isClosed?: boolean; color?: number[] | string; thickness?: number }): Mat | null;
|
|
599
|
+
function drawContours(mat: Mat, options: {
|
|
600
|
+
contours?: Point[][];
|
|
601
|
+
pts?: Point[][];
|
|
602
|
+
contourIdx?: number;
|
|
603
|
+
color?: number[] | string;
|
|
604
|
+
thickness?: number;
|
|
605
|
+
}): Mat | null;
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
就地绘制。`contourIdx` 为 `-1`(默认)表示画全部。
|
|
609
|
+
|
|
610
|
+
**示例:**
|
|
611
|
+
|
|
612
|
+
```javascript
|
|
613
|
+
cv.polylines(src, {
|
|
614
|
+
pts: [[{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 100, y: 80 }, { x: 0, y: 80 }]],
|
|
615
|
+
isClosed: true,
|
|
616
|
+
color: [0, 255, 0],
|
|
617
|
+
thickness: 2,
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## 模板匹配 / 轮廓 / 形态学
|
|
624
|
+
|
|
625
|
+
### matchTemplate / matchTemplateLoc
|
|
626
|
+
|
|
627
|
+
```typescript
|
|
628
|
+
function matchTemplate(image: Mat, templ: Mat, methodOrOptions?: number | { method?: number; mask?: Mat }): Mat | null;
|
|
629
|
+
function matchTemplateLoc(image: Mat, templ: Mat, methodOrOptions?: number | { method?: number }): MatchLocResult | null;
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**参数:**
|
|
633
|
+
|
|
634
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
635
|
+
| --- | --- | --- | --- | --- |
|
|
636
|
+
| `image` | Mat | 是 | - | 大图 |
|
|
637
|
+
| `templ` | Mat | 是 | - | 模板(须小于大图) |
|
|
638
|
+
| `method` | number | 否 | `TM_CCOEFF_NORMED` | 匹配方法 |
|
|
639
|
+
|
|
640
|
+
**matchTemplateLoc 返回:** `{ x, y, minVal, maxVal }`(最佳位置取自 max 或 min,取决于 method)。
|
|
641
|
+
|
|
642
|
+
**示例:**
|
|
643
|
+
|
|
644
|
+
```javascript
|
|
645
|
+
const loc = cv.matchTemplateLoc(src, templ, { method: cv.TM_CCOEFF_NORMED });
|
|
646
|
+
logi(`best=(${loc.x},${loc.y}) max=${loc.maxVal}`);
|
|
647
|
+
cv.rectangle(src, {
|
|
648
|
+
pt1: { x: loc.x, y: loc.y },
|
|
649
|
+
pt2: { x: loc.x + tw, y: loc.y + th },
|
|
650
|
+
color: [0, 0, 255],
|
|
651
|
+
thickness: 2,
|
|
652
|
+
});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### findContours
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
function findContours(mat: Mat, options?: { mode?: number; method?: number }): { contours: Point[][]; hierarchy: number[][] } | null;
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
**参数:**
|
|
662
|
+
|
|
663
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
664
|
+
| --- | --- | --- | --- | --- |
|
|
665
|
+
| `mode` | number | 否 | `RETR_EXTERNAL` | 如 `RETR_LIST` / `RETR_TREE` |
|
|
666
|
+
| `method` | number | 否 | `CHAIN_APPROX_SIMPLE` | 如 `CHAIN_APPROX_NONE` |
|
|
667
|
+
|
|
668
|
+
**返回值:** `contours` 为点集;`hierarchy` 为每个轮廓的 `[next, prev, child, parent]`(`-1` 表示无)。
|
|
669
|
+
|
|
670
|
+
输入一般为二值图。
|
|
671
|
+
|
|
672
|
+
**示例:**
|
|
673
|
+
|
|
674
|
+
```javascript
|
|
675
|
+
const { contours, hierarchy } = cv.findContours(bin, { mode: cv.RETR_TREE, method: cv.CHAIN_APPROX_SIMPLE });
|
|
676
|
+
logi(`count=${contours.length} h0=${hierarchy[0]}`);
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### boundingRect / minAreaRect / contourArea / arcLength / approxPolyDP / convexHull
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
function boundingRect(matOrPoints: Mat | Point[]): Rect | null;
|
|
683
|
+
function minAreaRect(points: Point[]): RotatedRect | null;
|
|
684
|
+
function contourArea(matOrPoints: Mat | Point[], orientedOrOptions?: boolean | { oriented?: boolean }): number;
|
|
685
|
+
function arcLength(points: Point[], closedOrOptions?: boolean | { closed?: boolean; isClosed?: boolean }): number;
|
|
686
|
+
function approxPolyDP(points: Point[], options: { epsilon?: number; closed?: boolean }): Point[] | null;
|
|
687
|
+
function convexHull(points: Point[], options?: { clockwise?: boolean }): Point[] | null;
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
**示例:**
|
|
691
|
+
|
|
692
|
+
```javascript
|
|
693
|
+
for (const c of contours) {
|
|
694
|
+
const area = cv.contourArea(c);
|
|
695
|
+
if (area < 100) continue;
|
|
696
|
+
const rect = cv.boundingRect(c);
|
|
697
|
+
const hull = cv.convexHull(c);
|
|
698
|
+
const approx = cv.approxPolyDP(c, { epsilon: 0.02 * cv.arcLength(c, true), closed: true });
|
|
699
|
+
cv.rectangle(src, { rect, color: [0, 255, 0], thickness: 1 });
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### moments / matchShapes
|
|
704
|
+
|
|
705
|
+
```typescript
|
|
706
|
+
function moments(mat: Mat, options?: { binaryImage?: boolean }): MomentsResult | null;
|
|
707
|
+
function moments(mat: Mat, binaryImage?: boolean): MomentsResult | null;
|
|
708
|
+
function moments(points: Point[]): MomentsResult | null;
|
|
709
|
+
function matchShapes(contour1: Mat, contour2: Mat, options?: { method?: number; parameter?: number }): number;
|
|
710
|
+
const cx = m.m10 / m.m00;
|
|
711
|
+
const cy = m.m01 / m.m00;
|
|
712
|
+
const score = cv.matchShapes(c1, c2, { method: cv.CONTOURS_MATCH_I1 });
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### erode / dilate / morphologyEx / getStructuringElement
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
function getStructuringElement(options: { shape?: number; ksize: number | [number, number] | Size }): Mat | null;
|
|
719
|
+
const opened = cv.morphologyEx(bin, { op: cv.MORPH_OPEN, kernel: k });
|
|
720
|
+
cv.release(k);
|
|
721
|
+
cv.release(opened);
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### connectedComponentsWithStats / distanceTransform / floodFill / goodFeaturesToTrack
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
function connectedComponentsWithStats(mat: Mat): {
|
|
728
|
+
count: number;
|
|
729
|
+
labels: Mat | null;
|
|
730
|
+
stats: Mat | null;
|
|
731
|
+
centroids: Mat | null;
|
|
732
|
+
} | null;
|
|
733
|
+
|
|
734
|
+
function distanceTransform(mat: Mat, options?: { distanceType?: number; maskSize?: number }): Mat | null;
|
|
735
|
+
|
|
736
|
+
function floodFill(mat: Mat, options: {
|
|
737
|
+
seedPoint: Point | [number, number];
|
|
738
|
+
newVal: number[] | string;
|
|
739
|
+
loDiff?: number[] | string;
|
|
740
|
+
upDiff?: number[] | string;
|
|
741
|
+
}): { filled: number; rect: Rect } | null;
|
|
742
|
+
|
|
743
|
+
function goodFeaturesToTrack(mat: Mat, options: {
|
|
744
|
+
maxCorners?: number;
|
|
745
|
+
qualityLevel?: number;
|
|
746
|
+
minDistance?: number;
|
|
747
|
+
mask?: Mat;
|
|
748
|
+
}): Point[] | null;
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
**说明:**
|
|
752
|
+
|
|
753
|
+
- `connectedComponentsWithStats`:`stats` 可用 `CC_STAT_LEFT/TOP/WIDTH/HEIGHT/AREA` 读列。
|
|
754
|
+
- `floodFill` **就地**修改输入图。
|
|
755
|
+
- `goodFeaturesToTrack`:Shi-Tomasi 角点,输入建议灰度。
|
|
756
|
+
|
|
757
|
+
**示例:**
|
|
758
|
+
|
|
759
|
+
```javascript
|
|
760
|
+
const cc = cv.connectedComponentsWithStats(bin);
|
|
761
|
+
logi(`components=${cc.count}`);
|
|
762
|
+
cv.release(cc.labels);
|
|
763
|
+
cv.release(cc.stats);
|
|
764
|
+
cv.release(cc.centroids);
|
|
765
|
+
|
|
766
|
+
const corners = cv.goodFeaturesToTrack(gray, {
|
|
767
|
+
maxCorners: 50,
|
|
768
|
+
qualityLevel: 0.01,
|
|
769
|
+
minDistance: 10,
|
|
770
|
+
});
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### HoughLinesP / HoughCircles
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
function HoughLinesP(mat: Mat, options: {
|
|
777
|
+
rho?: number; theta?: number; threshold?: number;
|
|
778
|
+
minLineLength?: number; maxLineGap?: number;
|
|
779
|
+
}): Array<{ x1: number; y1: number; x2: number; y2: number }> | null;
|
|
780
|
+
|
|
781
|
+
function HoughCircles(mat: Mat, options: {
|
|
782
|
+
method?: number; dp?: number; minDist?: number;
|
|
783
|
+
param1?: number; param2?: number;
|
|
784
|
+
minRadius?: number; maxRadius?: number;
|
|
785
|
+
}): Array<{ x: number; y: number; radius: number }> | null;
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
输入一般为边缘图(直线)或灰度图(圆)。`method` 常用 `cv.HOUGH_GRADIENT`。
|
|
789
|
+
|
|
790
|
+
**示例:**
|
|
791
|
+
|
|
792
|
+
```javascript
|
|
793
|
+
const lines = cv.HoughLinesP(edges, {
|
|
794
|
+
rho: 1,
|
|
795
|
+
theta: Math.PI / 180,
|
|
796
|
+
threshold: 80,
|
|
797
|
+
minLineLength: 40,
|
|
798
|
+
maxLineGap: 10,
|
|
799
|
+
});
|
|
800
|
+
for (const l of lines) {
|
|
801
|
+
cv.line(src, { pt1: { x: l.x1, y: l.y1 }, pt2: { x: l.x2, y: l.y2 }, color: [0, 255, 0], thickness: 1 });
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const circles = cv.HoughCircles(gray, {
|
|
805
|
+
method: cv.HOUGH_GRADIENT,
|
|
806
|
+
dp: 1,
|
|
807
|
+
minDist: 30,
|
|
808
|
+
param1: 100,
|
|
809
|
+
param2: 30,
|
|
810
|
+
minRadius: 10,
|
|
811
|
+
maxRadius: 80,
|
|
812
|
+
});
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
---
|
|
816
|
+
|
|
817
|
+
## 算术 / 直方图 / Flann / 扫码 / 矩阵
|
|
818
|
+
|
|
819
|
+
### add / subtract / multiply / divide
|
|
820
|
+
|
|
821
|
+
```typescript
|
|
822
|
+
function add(src1: Mat, options: { src2: Mat; mask?: Mat }): Mat | null;
|
|
823
|
+
function subtract(src1: Mat, options: { src2: Mat; mask?: Mat }): Mat | null;
|
|
824
|
+
function multiply(src1: Mat, options: { src2: Mat; scale?: number }): Mat | null;
|
|
825
|
+
function divide(src1: Mat, options: { src2: Mat; scale?: number }): Mat | null;
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
**示例:**
|
|
829
|
+
|
|
830
|
+
```javascript
|
|
831
|
+
const sum = cv.add(a, { src2: b });
|
|
832
|
+
const scaled = cv.multiply(a, { src2: b, scale: 0.5 });
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
### normalize / norm / meanStdDev / findNonZero / hconcat / vconcat
|
|
836
|
+
|
|
837
|
+
```typescript
|
|
838
|
+
function normalize(mat: Mat, options?: { alpha?: number; beta?: number; normType?: number }): Mat | null;
|
|
839
|
+
function norm(mat: Mat, options?: { normType?: number; mask?: Mat; src2?: Mat }): number;
|
|
840
|
+
function meanStdDev(mat: Mat, options?: { mask?: Mat }): { mean: number[]; stddev: number[] } | null;
|
|
841
|
+
function findNonZero(mat: Mat): Point[] | null;
|
|
842
|
+
function hconcat(mats: Mat[]): Mat | null;
|
|
843
|
+
function vconcat(mats: Mat[]): Mat | null;
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
**示例:**
|
|
847
|
+
|
|
848
|
+
```javascript
|
|
849
|
+
const n01 = cv.normalize(gray, { alpha: 0, beta: 255, normType: cv.NORM_MINMAX });
|
|
850
|
+
const pts = cv.findNonZero(mask);
|
|
851
|
+
const side = cv.hconcat([left, right]);
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### getPerspectiveTransform / getAffineTransform
|
|
855
|
+
|
|
856
|
+
已知对应点求变换矩阵。透视 ≥4 点,仿射 ≥3 点。
|
|
857
|
+
|
|
858
|
+
```typescript
|
|
859
|
+
function getPerspectiveTransform(options: { srcPoints: Point[]; dstPoints: Point[] }): Mat | null;
|
|
860
|
+
function getAffineTransform(options: { srcPoints: Point[]; dstPoints: Point[] }): Mat | null;
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
**示例:**
|
|
864
|
+
|
|
865
|
+
```javascript
|
|
866
|
+
const M = cv.getPerspectiveTransform({
|
|
867
|
+
srcPoints: [{ x: 10, y: 10 }, { x: 200, y: 20 }, { x: 190, y: 300 }, { x: 20, y: 280 }],
|
|
868
|
+
dstPoints: [{ x: 0, y: 0 }, { x: 300, y: 0 }, { x: 300, y: 400 }, { x: 0, y: 400 }],
|
|
869
|
+
});
|
|
870
|
+
const warped = cv.warpPerspective(src, { M, width: 300, height: 400 });
|
|
871
|
+
cv.release(M);
|
|
872
|
+
cv.release(warped);
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
### FlannBasedMatcher / flannKnnMatch
|
|
876
|
+
|
|
877
|
+
```typescript
|
|
878
|
+
function FlannBasedMatcher(queryDescriptors: Mat, trainDescriptors: Mat): DMatch[] | null;
|
|
879
|
+
function flannKnnMatch(queryDescriptors: Mat, trainDescriptors: Mat, options?: { k?: number; ratio?: number }): DMatch[][] | null;
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
SIFT 等浮点描述子可用 Flann;ORB 建议 `BFMatcher` + `NORM_HAMMING`。
|
|
883
|
+
|
|
884
|
+
**示例:**
|
|
885
|
+
|
|
886
|
+
```javascript
|
|
887
|
+
const knn = cv.flannKnnMatch(f2.descriptors, f1.descriptors, { k: 2, ratio: 0.75 });
|
|
888
|
+
const good = knn.map((g) => g[0]);
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
### calcHist / compareHist
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
function calcHist(mat: Mat, options?: { channels?: number[]; histSize?: number[]; ranges?: number[]; mask?: Mat; accumulate?: boolean }): Mat | null;
|
|
895
|
+
function compareHist(H1: Mat, H2: Mat, options?: { method?: number }): number;
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
默认通道 `[0]`、`histSize [256]`、`ranges [0,256]`。
|
|
899
|
+
|
|
900
|
+
**示例:**
|
|
901
|
+
|
|
902
|
+
```javascript
|
|
903
|
+
const h1 = cv.calcHist(gray1);
|
|
904
|
+
const h2 = cv.calcHist(gray2);
|
|
905
|
+
const score = cv.compareHist(h1, h2, { method: cv.HISTCMP_CORREL });
|
|
906
|
+
cv.release(h1); cv.release(h2);
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
### boxPoints / pointPolygonTest / minEnclosingCircle / fitEllipse
|
|
910
|
+
|
|
911
|
+
```typescript
|
|
912
|
+
function boxPoints(options: { center: Point; size: Size | [number, number]; angle?: number }): Point[] | null;
|
|
913
|
+
function pointPolygonTest(contour: Point[], ptOrOptions: Point | { pt: Point; measureDist?: boolean }): number;
|
|
914
|
+
function minEnclosingCircle(points: Point[]): { center: Point; radius: number } | null;
|
|
915
|
+
function fitEllipse(points: Point[]): RotatedRect | null;
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
**示例:**
|
|
919
|
+
|
|
920
|
+
```javascript
|
|
921
|
+
const rr = cv.minAreaRect(contour);
|
|
922
|
+
const corners = cv.boxPoints(rr);
|
|
923
|
+
const inside = cv.pointPolygonTest(contour, { pt: { x: 100, y: 100 } });
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
### detectQRCode / detectBarcode
|
|
927
|
+
|
|
928
|
+
```typescript
|
|
929
|
+
function detectQRCode(mat: Mat): { decoded: string; points: Point[] } | null;
|
|
930
|
+
function detectBarcode(mat: Mat): { decoded: string[]; types: string[]; points: Point[] } | null;
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
**示例:**
|
|
934
|
+
|
|
935
|
+
```javascript
|
|
936
|
+
const qr = cv.detectQRCode(src);
|
|
937
|
+
if (qr) logi(qr.decoded);
|
|
938
|
+
const codes = cv.detectBarcode(src);
|
|
939
|
+
if (codes) logi(codes.decoded.join(","));
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
### filter2D / ellipse / getTextSize
|
|
943
|
+
|
|
944
|
+
```typescript
|
|
945
|
+
function filter2D(mat: Mat, options: { kernel: Mat; ddepth?: number; delta?: number }): Mat | null;
|
|
946
|
+
function ellipse(mat: Mat, options: { center: Point; axes: Size | [number, number]; angle?: number; startAngle?: number; endAngle?: number; color?: number[] | string; thickness?: number }): Mat | null;
|
|
947
|
+
function getTextSize(options: { text: string; fontFace?: number; fontScale?: number; thickness?: number }): { width: number; height: number; baseLine: number } | null;
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
`ellipse` 就地绘制;`thickness: cv.FILLED` 表示填充。
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
## 特征点 / 描述子 / 匹配 / 单应
|
|
955
|
+
|
|
956
|
+
### 返回结构
|
|
957
|
+
|
|
958
|
+
**KeyPoint:**
|
|
959
|
+
|
|
960
|
+
| 字段 | 类型 | 描述 |
|
|
961
|
+
| --- | --- | --- |
|
|
962
|
+
| `x` / `y` | number | 坐标 |
|
|
963
|
+
| `size` | number | 邻域直径 |
|
|
964
|
+
| `angle` | number | 方向;不适用为 `-1` |
|
|
965
|
+
| `response` | number | 响应强度 |
|
|
966
|
+
| `octave` | number | 金字塔层 |
|
|
967
|
+
| `class_id` | number | 类别 id |
|
|
968
|
+
|
|
969
|
+
**DMatch:**
|
|
970
|
+
|
|
971
|
+
| 字段 | 类型 | 描述 |
|
|
972
|
+
| --- | --- | --- |
|
|
973
|
+
| `queryIdx` | number | 查询描述子索引 |
|
|
974
|
+
| `trainIdx` | number | 训练描述子索引 |
|
|
975
|
+
| `distance` | number | 距离(越小越相似) |
|
|
976
|
+
|
|
977
|
+
**FeatureResult:** `{ keypoints: KeyPoint[], descriptors: Mat | null }`
|
|
978
|
+
描述子是 Mat 句柄,用完需 `cv.release(descriptors)`。
|
|
979
|
+
|
|
980
|
+
### SIFT
|
|
981
|
+
|
|
982
|
+
```typescript
|
|
983
|
+
function SIFT(mat: Mat, options?: {
|
|
984
|
+
nfeatures?: number;
|
|
985
|
+
nOctaveLayers?: number;
|
|
986
|
+
contrastThreshold?: number;
|
|
987
|
+
edgeThreshold?: number;
|
|
988
|
+
sigma?: number;
|
|
989
|
+
mask?: Mat;
|
|
990
|
+
}): FeatureResult | null;
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
**参数:**
|
|
994
|
+
|
|
995
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
996
|
+
| --- | --- | --- | --- | --- |
|
|
997
|
+
| `mat` | Mat | 是 | - | 输入图(建议灰度) |
|
|
998
|
+
| `nfeatures` | number | 否 | 0(不限制) | 保留最佳特征数量 |
|
|
999
|
+
| `nOctaveLayers` | number | 否 | 3 | 每组 octave 层数 |
|
|
1000
|
+
| `contrastThreshold` | number | 否 | 0.04 | 对比度阈值,越大特征越少 |
|
|
1001
|
+
| `edgeThreshold` | number | 否 | 10 | 边缘过滤阈值 |
|
|
1002
|
+
| `sigma` | number | 否 | 1.6 | 第 0 层高斯 sigma |
|
|
1003
|
+
| `mask` | Mat | 否 | - | 可选 ROI 掩膜 |
|
|
1004
|
+
|
|
1005
|
+
**返回值:** `{ keypoints, descriptors }`;失败 `null`。
|
|
1006
|
+
|
|
1007
|
+
**示例:**
|
|
1008
|
+
|
|
1009
|
+
```javascript
|
|
1010
|
+
const gray = cv.cvtColor(src, { code: cv.COLOR_BGR2GRAY });
|
|
1011
|
+
const feat = cv.SIFT(gray, { nfeatures: 500 });
|
|
1012
|
+
if (feat) {
|
|
1013
|
+
logi(`SIFT keypoints=${feat.keypoints.length}`);
|
|
1014
|
+
const vis = cv.drawKeypoints(src, { keypoints: feat.keypoints, color: [0, 255, 0] });
|
|
1015
|
+
cv.imwrite(`${file.getInternalDir("documents")}/sift.png`, vis);
|
|
1016
|
+
cv.release(vis);
|
|
1017
|
+
cv.release(feat.descriptors);
|
|
1018
|
+
}
|
|
1019
|
+
cv.release(gray);
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
### ORB
|
|
1023
|
+
|
|
1024
|
+
```typescript
|
|
1025
|
+
function ORB(mat: Mat, options?: {
|
|
1026
|
+
nfeatures?: number;
|
|
1027
|
+
scaleFactor?: number;
|
|
1028
|
+
nlevels?: number;
|
|
1029
|
+
mask?: Mat;
|
|
1030
|
+
}): FeatureResult | null;
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
**参数:**
|
|
1034
|
+
|
|
1035
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
1036
|
+
| --- | --- | --- | --- | --- |
|
|
1037
|
+
| `nfeatures` | number | 否 | 500 | 最大特征数 |
|
|
1038
|
+
| `scaleFactor` | number | 否 | 1.2 | 金字塔尺度因子 |
|
|
1039
|
+
| `nlevels` | number | 否 | 8 | 金字塔层数 |
|
|
1040
|
+
|
|
1041
|
+
**说明:** ORB 描述子为二进制,匹配请用 `cv.NORM_HAMMING`(或 `NORM_HAMMING2`)。实时/循环优先 ORB。
|
|
1042
|
+
|
|
1043
|
+
**示例:**
|
|
1044
|
+
|
|
1045
|
+
```javascript
|
|
1046
|
+
const a = cv.ORB(img1, { nfeatures: 800 });
|
|
1047
|
+
const b = cv.ORB(img2, { nfeatures: 800 });
|
|
1048
|
+
const matches = cv.BFMatcher(a.descriptors, b.descriptors, {
|
|
1049
|
+
normType: cv.NORM_HAMMING,
|
|
1050
|
+
crossCheck: true,
|
|
1051
|
+
});
|
|
1052
|
+
logi(`matches=${matches.length}`);
|
|
1053
|
+
cv.release(a.descriptors);
|
|
1054
|
+
cv.release(b.descriptors);
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
### AKAZE / BRISK / FAST
|
|
1058
|
+
|
|
1059
|
+
```typescript
|
|
1060
|
+
function AKAZE(mat: Mat, options?: { mask?: Mat }): FeatureResult | null;
|
|
1061
|
+
function BRISK(mat: Mat, options?: { thresh?: number; octaves?: number; mask?: Mat }): FeatureResult | null;
|
|
1062
|
+
function FAST(mat: Mat, options?: { threshold?: number; nonmaxSuppression?: boolean; mask?: Mat }): { keypoints: KeyPoint[] } | null;
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
**说明:**
|
|
1066
|
+
|
|
1067
|
+
- `AKAZE` / `BRISK` 返回关键点 + 描述子。
|
|
1068
|
+
- `FAST` **只检测关键点**,无 `descriptors`。
|
|
1069
|
+
- `BRISK`:`thresh` 默认 30,`octaves` 默认 3。
|
|
1070
|
+
- `FAST`:`threshold` 默认 10,`nonmaxSuppression` 默认 `true`。
|
|
1071
|
+
|
|
1072
|
+
**示例:**
|
|
1073
|
+
|
|
1074
|
+
```javascript
|
|
1075
|
+
const fast = cv.FAST(gray, { threshold: 20 });
|
|
1076
|
+
logi(`FAST count=${fast.keypoints.length}`);
|
|
1077
|
+
const brisk = cv.BRISK(gray, { thresh: 30, octaves: 3 });
|
|
1078
|
+
cv.release(brisk.descriptors);
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
### BFMatcher
|
|
1082
|
+
|
|
1083
|
+
```typescript
|
|
1084
|
+
function BFMatcher(queryDescriptors: Mat, trainDescriptors: Mat, options?: {
|
|
1085
|
+
normType?: number;
|
|
1086
|
+
crossCheck?: boolean;
|
|
1087
|
+
}): DMatch[] | null;
|
|
1088
|
+
matches.sort((a, b) => a.distance - b.distance);
|
|
1089
|
+
const top = matches.slice(0, 30);
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
### knnMatch
|
|
1093
|
+
|
|
1094
|
+
```typescript
|
|
1095
|
+
function knnMatch(queryDescriptors: Mat, trainDescriptors: Mat, options?: {
|
|
1096
|
+
k?: number;
|
|
1097
|
+
normType?: number;
|
|
1098
|
+
ratio?: number;
|
|
1099
|
+
}): DMatch[][] | null;
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
**参数:**
|
|
1103
|
+
|
|
1104
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
1105
|
+
| --- | --- | --- | --- | --- |
|
|
1106
|
+
| `k` | number | 否 | 2 | 每个查询点取 K 个最近邻 |
|
|
1107
|
+
| `normType` | number | 否 | `NORM_L2` | 距离类型 |
|
|
1108
|
+
| `ratio` | number | 否 | - | 如 `0.75`:启用 Lowe ratio test,只保留通过筛选的最近邻 |
|
|
1109
|
+
|
|
1110
|
+
**返回值:**
|
|
1111
|
+
|
|
1112
|
+
- 未设 `ratio`:`DMatch[][]`,外层每个查询一组。
|
|
1113
|
+
- 设了 `ratio`:仅保留通过筛选的组,每组通常只含 1 个 `DMatch`。
|
|
1114
|
+
|
|
1115
|
+
**示例:**
|
|
1116
|
+
|
|
1117
|
+
```javascript
|
|
1118
|
+
const knn = cv.knnMatch(desc1, desc2, {
|
|
1119
|
+
k: 2,
|
|
1120
|
+
normType: cv.NORM_L2,
|
|
1121
|
+
ratio: 0.75,
|
|
1122
|
+
});
|
|
1123
|
+
const good = knn.map((g) => g[0]);
|
|
1124
|
+
logi(`good matches=${good.length}`);
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
### drawKeypoints / drawMatches
|
|
1128
|
+
|
|
1129
|
+
```typescript
|
|
1130
|
+
function drawKeypoints(mat: Mat, options: { keypoints: KeyPoint[]; color?: number[] | string }): Mat | null;
|
|
1131
|
+
function drawMatches(img1: Mat, options: {
|
|
1132
|
+
img2: Mat;
|
|
1133
|
+
keypoints1: KeyPoint[];
|
|
1134
|
+
keypoints2: KeyPoint[];
|
|
1135
|
+
matches1to2: DMatch[];
|
|
1136
|
+
}): Mat | null;
|
|
1137
|
+
cv.imwrite(`${file.getInternalDir("documents")}/matches.png`, vis);
|
|
1138
|
+
cv.release(vis);
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
### findHomography / perspectiveTransform / warpPerspective
|
|
1142
|
+
|
|
1143
|
+
```typescript
|
|
1144
|
+
function findHomography(options: {
|
|
1145
|
+
srcPoints: Point[];
|
|
1146
|
+
dstPoints: Point[];
|
|
1147
|
+
method?: number;
|
|
1148
|
+
ransacReprojThreshold?: number;
|
|
1149
|
+
}): Mat | null;
|
|
1150
|
+
|
|
1151
|
+
function perspectiveTransform(points: Point[], options: { M: Mat }): Point[] | null;
|
|
1152
|
+
const templ = cv.imread("logo.png");
|
|
1153
|
+
const g1 = cv.cvtColor(src, { code: cv.COLOR_BGR2GRAY });
|
|
1154
|
+
const g2 = cv.cvtColor(templ, { code: cv.COLOR_BGR2GRAY });
|
|
1155
|
+
|
|
1156
|
+
const f1 = cv.SIFT(g1, { nfeatures: 800 });
|
|
1157
|
+
const f2 = cv.SIFT(g2, { nfeatures: 800 });
|
|
1158
|
+
const knn = cv.flannKnnMatch(f2.descriptors, f1.descriptors, {
|
|
1159
|
+
k: 2,
|
|
1160
|
+
ratio: 0.75,
|
|
1161
|
+
});
|
|
1162
|
+
const good = knn.map((g) => g[0]);
|
|
1163
|
+
|
|
1164
|
+
if (good.length >= 4) {
|
|
1165
|
+
const srcPts = good.map((m) => ({
|
|
1166
|
+
x: f2.keypoints[m.queryIdx].x,
|
|
1167
|
+
y: f2.keypoints[m.queryIdx].y,
|
|
1168
|
+
}));
|
|
1169
|
+
const dstPts = good.map((m) => ({
|
|
1170
|
+
x: f1.keypoints[m.trainIdx].x,
|
|
1171
|
+
y: f1.keypoints[m.trainIdx].y,
|
|
1172
|
+
}));
|
|
1173
|
+
const H = cv.findHomography({
|
|
1174
|
+
srcPoints: srcPts,
|
|
1175
|
+
dstPoints: dstPts,
|
|
1176
|
+
method: cv.RANSAC,
|
|
1177
|
+
ransacReprojThreshold: 5,
|
|
1178
|
+
});
|
|
1179
|
+
const w = cv.getSize(templ).width;
|
|
1180
|
+
const h = cv.getSize(templ).height;
|
|
1181
|
+
const corners = cv.perspectiveTransform(
|
|
1182
|
+
[
|
|
1183
|
+
{ x: 0, y: 0 },
|
|
1184
|
+
{ x: w, y: 0 },
|
|
1185
|
+
{ x: w, y: h },
|
|
1186
|
+
{ x: 0, y: h },
|
|
1187
|
+
],
|
|
1188
|
+
{ M: H },
|
|
1189
|
+
);
|
|
1190
|
+
cv.polylines(src, { pts: [corners], isClosed: true, color: [0, 255, 0], thickness: 2 });
|
|
1191
|
+
cv.release(H);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
cv.release(src);
|
|
1195
|
+
cv.release(templ);
|
|
1196
|
+
cv.release(g1);
|
|
1197
|
+
cv.release(g2);
|
|
1198
|
+
cv.release(f1.descriptors);
|
|
1199
|
+
cv.release(f2.descriptors);
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
---
|
|
1203
|
+
|
|
1204
|
+
## Photo / 修复与风格化
|
|
1205
|
+
|
|
1206
|
+
### inpaint
|
|
1207
|
+
|
|
1208
|
+
```typescript
|
|
1209
|
+
function inpaint(mat: Mat, options: { mask: Mat; inpaintRadius?: number; flags?: number }): Mat | null;
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
1213
|
+
| --- | --- | --- | --- | --- |
|
|
1214
|
+
| `mask` | Mat | 是 | - | 非零区域待修复 |
|
|
1215
|
+
| `inpaintRadius` | number | 否 | 3 | 邻域半径 |
|
|
1216
|
+
| `flags` | number | 否 | `INPAINT_TELEA` | `INPAINT_NS` / `INPAINT_TELEA` |
|
|
1217
|
+
|
|
1218
|
+
```javascript
|
|
1219
|
+
const out = cv.inpaint(src, { mask, flags: cv.INPAINT_TELEA });
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
### fastNlMeansDenoising / fastNlMeansDenoisingColored
|
|
1223
|
+
|
|
1224
|
+
```typescript
|
|
1225
|
+
function fastNlMeansDenoising(mat: Mat, options?: {
|
|
1226
|
+
h?: number; templateWindowSize?: number; searchWindowSize?: number;
|
|
1227
|
+
}): Mat | null;
|
|
1228
|
+
function fastNlMeansDenoisingColored(mat: Mat, options?: {
|
|
1229
|
+
h?: number; hColor?: number; templateWindowSize?: number; searchWindowSize?: number;
|
|
1230
|
+
}): Mat | null;
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
```javascript
|
|
1234
|
+
const d1 = cv.fastNlMeansDenoising(gray, { h: 3 });
|
|
1235
|
+
const d2 = cv.fastNlMeansDenoisingColored(src, { h: 3, hColor: 3 });
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
### edgePreservingFilter / detailEnhance / stylization
|
|
1239
|
+
|
|
1240
|
+
```typescript
|
|
1241
|
+
function edgePreservingFilter(mat: Mat, options?: { flags?: number; sigma_s?: number; sigma_r?: number }): Mat | null;
|
|
1242
|
+
function detailEnhance(mat: Mat, options?: { sigma_s?: number; sigma_r?: number }): Mat | null;
|
|
1243
|
+
function stylization(mat: Mat, options?: { sigma_s?: number; sigma_r?: number }): Mat | null;
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
```javascript
|
|
1247
|
+
const soft = cv.edgePreservingFilter(src, { flags: cv.RECURS_FILTER });
|
|
1248
|
+
const sharp = cv.detailEnhance(src);
|
|
1249
|
+
const art = cv.stylization(src);
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
### pencilSketch / decolor
|
|
1253
|
+
|
|
1254
|
+
```typescript
|
|
1255
|
+
function pencilSketch(mat: Mat, options?: {
|
|
1256
|
+
sigma_s?: number; sigma_r?: number; shade_factor?: number;
|
|
1257
|
+
}): { gray: Mat; color: Mat } | null;
|
|
1258
|
+
function decolor(mat: Mat): { grayscale: Mat; colorBoost: Mat } | null;
|
|
1259
|
+
```
|
|
1260
|
+
|
|
1261
|
+
返回两个新句柄,用完需分别 `release`。
|
|
1262
|
+
|
|
1263
|
+
```javascript
|
|
1264
|
+
const sketch = cv.pencilSketch(src);
|
|
1265
|
+
const dc = cv.decolor(src);
|
|
1266
|
+
cv.release(sketch.gray); cv.release(sketch.color);
|
|
1267
|
+
cv.release(dc.grayscale); cv.release(dc.colorBoost);
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
### seamlessClone
|
|
1271
|
+
|
|
1272
|
+
```typescript
|
|
1273
|
+
function seamlessClone(src: Mat, options: {
|
|
1274
|
+
dst: Mat; mask: Mat; p?: Point; x?: number; y?: number; flags?: number;
|
|
1275
|
+
}): Mat | null;
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
1279
|
+
| --- | --- | --- | --- | --- |
|
|
1280
|
+
| `dst` | Mat | 是 | - | 背景图 |
|
|
1281
|
+
| `mask` | Mat | 是 | - | 前景有效区域 |
|
|
1282
|
+
| `p` / `x,y` | Point | 是 | - | 贴入中心 |
|
|
1283
|
+
| `flags` | number | 否 | `NORMAL_CLONE` | `NORMAL_CLONE` / `MIXED_CLONE` / `MONOCHROME_TRANSFER` |
|
|
1284
|
+
|
|
1285
|
+
```javascript
|
|
1286
|
+
const blend = cv.seamlessClone(fg, { dst: bg, mask, p: { x: 200, y: 150 }, flags: cv.NORMAL_CLONE });
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
### colorChange / illuminationChange / textureFlattening
|
|
1290
|
+
|
|
1291
|
+
```typescript
|
|
1292
|
+
function colorChange(mat: Mat, options: { mask: Mat; red_mul?: number; green_mul?: number; blue_mul?: number }): Mat | null;
|
|
1293
|
+
function illuminationChange(mat: Mat, options: { mask: Mat; alpha?: number; beta?: number }): Mat | null;
|
|
1294
|
+
function textureFlattening(mat: Mat, options: {
|
|
1295
|
+
mask: Mat; low_threshold?: number; high_threshold?: number; kernel_size?: number;
|
|
1296
|
+
}): Mat | null;
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
```javascript
|
|
1300
|
+
const c = cv.colorChange(src, { mask, red_mul: 1.5, green_mul: 1.0, blue_mul: 0.8 });
|
|
1301
|
+
const i = cv.illuminationChange(src, { mask, alpha: 0.2, beta: 0.4 });
|
|
1302
|
+
const f = cv.textureFlattening(src, { mask });
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1305
|
+
---
|
|
1306
|
+
|
|
1307
|
+
## Core 扩展
|
|
1308
|
+
|
|
1309
|
+
### LUT / compare / min / max
|
|
1310
|
+
|
|
1311
|
+
```typescript
|
|
1312
|
+
function LUT(mat: Mat, options: { lut: Mat }): Mat | null;
|
|
1313
|
+
function compare(src1: Mat, options: { src2: Mat; cmpop: number }): Mat | null;
|
|
1314
|
+
function min(src1: Mat, options: { src2: Mat }): Mat | null;
|
|
1315
|
+
function max(src1: Mat, options: { src2: Mat }): Mat | null;
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
`cmpop` 使用 `CMP_EQ` / `CMP_GT` / `CMP_GE` / `CMP_LT` / `CMP_LE` / `CMP_NE`。
|
|
1319
|
+
|
|
1320
|
+
```javascript
|
|
1321
|
+
const mask = cv.compare(a, { src2: b, cmpop: cv.CMP_GT });
|
|
1322
|
+
const lo = cv.min(a, { src2: b });
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
### extractChannel / insertChannel / mixChannels
|
|
1326
|
+
|
|
1327
|
+
```typescript
|
|
1328
|
+
function extractChannel(mat: Mat, options: { coi: number }): Mat | null;
|
|
1329
|
+
/** 就地写入 dst,返回 dst 句柄 */
|
|
1330
|
+
function insertChannel(srcChannel: Mat, options: { dst: Mat; coi: number }): Mat | null;
|
|
1331
|
+
/** 就地改写 dst,成功返回 true */
|
|
1332
|
+
function mixChannels(options: { src: Mat[]; dst: Mat[]; fromTo: number[] }): boolean;
|
|
1333
|
+
```
|
|
1334
|
+
|
|
1335
|
+
```javascript
|
|
1336
|
+
const b = cv.extractChannel(src, { coi: 0 });
|
|
1337
|
+
cv.insertChannel(b, { dst: out, coi: 0 }); // 就地改 out
|
|
1338
|
+
cv.mixChannels({ src: [src], dst: [out], fromTo: [0, 2, 1, 1, 2, 0] });
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
### pow / sqrt / exp / log / magnitude / cartToPolar / polarToCart
|
|
1342
|
+
|
|
1343
|
+
```typescript
|
|
1344
|
+
function pow(mat: Mat, options: { power: number }): Mat | null;
|
|
1345
|
+
function sqrt(mat: Mat): Mat | null;
|
|
1346
|
+
function exp(mat: Mat): Mat | null;
|
|
1347
|
+
function log(mat: Mat): Mat | null;
|
|
1348
|
+
function magnitude(options: { x: Mat; y: Mat }): Mat | null;
|
|
1349
|
+
function cartToPolar(options: { x: Mat; y: Mat; angleInDegrees?: boolean }): { magnitude: Mat; angle: Mat } | null;
|
|
1350
|
+
function polarToCart(options: { magnitude: Mat; angle: Mat; angleInDegrees?: boolean }): { x: Mat; y: Mat } | null;
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
```javascript
|
|
1354
|
+
const mag = cv.magnitude({ x: dx, y: dy });
|
|
1355
|
+
const polar = cv.cartToPolar({ x: dx, y: dy, angleInDegrees: true });
|
|
1356
|
+
cv.release(polar.magnitude); cv.release(polar.angle);
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
### PSNR / scaleAdd / sum
|
|
1360
|
+
|
|
1361
|
+
```typescript
|
|
1362
|
+
function PSNR(src1: Mat, options: { src2: Mat; R?: number }): number;
|
|
1363
|
+
function scaleAdd(src1: Mat, options: { alpha: number; src2: Mat }): Mat | null;
|
|
1364
|
+
function sum(mat: Mat): number[] | null;
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
```javascript
|
|
1368
|
+
const psnr = cv.PSNR(a, { src2: b });
|
|
1369
|
+
const s = cv.sum(src); // 各通道和
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
---
|
|
1373
|
+
|
|
1374
|
+
## Imgproc 几何 / 滤波扩展
|
|
1375
|
+
|
|
1376
|
+
### stackBlur / sepFilter2D / remap / warpPolar
|
|
1377
|
+
|
|
1378
|
+
```typescript
|
|
1379
|
+
function stackBlur(mat: Mat, options: { ksize: number | [number, number] | Size }): Mat | null;
|
|
1380
|
+
function sepFilter2D(mat: Mat, options: { kernelX: Mat; kernelY: Mat; ddepth?: number; delta?: number }): Mat | null;
|
|
1381
|
+
function remap(mat: Mat, options: { map1: Mat; map2: Mat; interpolation?: number; borderMode?: number }): Mat | null;
|
|
1382
|
+
function warpPolar(mat: Mat, options: {
|
|
1383
|
+
width?: number; height?: number;
|
|
1384
|
+
center: Point; maxRadius: number; flags?: number;
|
|
1385
|
+
}): Mat | null;
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
```javascript
|
|
1389
|
+
const blur = cv.stackBlur(src, { ksize: 7 });
|
|
1390
|
+
const polar = cv.warpPolar(src, {
|
|
1391
|
+
width: 300, height: 300, center: { x: 160, y: 160 }, maxRadius: 150,
|
|
1392
|
+
flags: cv.INTER_LINEAR | cv.WARP_POLAR_LINEAR,
|
|
1393
|
+
});
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
### invertAffineTransform / getRectSubPix / phaseCorrelate
|
|
1397
|
+
|
|
1398
|
+
```typescript
|
|
1399
|
+
function invertAffineTransform(M: Mat): Mat | null;
|
|
1400
|
+
function getRectSubPix(mat: Mat, options: {
|
|
1401
|
+
patchSize: Size | [number, number]; center: Point;
|
|
1402
|
+
}): Mat | null;
|
|
1403
|
+
function phaseCorrelate(src1: Mat, options: { src2: Mat; window?: Mat }): {
|
|
1404
|
+
x: number; y: number; response?: number;
|
|
1405
|
+
} | null;
|
|
1406
|
+
```
|
|
1407
|
+
|
|
1408
|
+
```javascript
|
|
1409
|
+
const inv = cv.invertAffineTransform(M);
|
|
1410
|
+
const shift = cv.phaseCorrelate(a, { src2: b });
|
|
1411
|
+
```
|
|
1412
|
+
|
|
1413
|
+
### HoughLines / LSD
|
|
1414
|
+
|
|
1415
|
+
```typescript
|
|
1416
|
+
function HoughLines(mat: Mat, options?: {
|
|
1417
|
+
rho?: number; theta?: number; threshold?: number; srn?: number; stn?: number;
|
|
1418
|
+
}): Array<{ rho: number; theta: number }> | null;
|
|
1419
|
+
function LSD(mat: Mat, options?: object): Array<{ x1: number; y1: number; x2: number; y2: number }> | null;
|
|
1420
|
+
```
|
|
1421
|
+
|
|
1422
|
+
```javascript
|
|
1423
|
+
const lines = cv.HoughLines(edges, { threshold: 80 });
|
|
1424
|
+
const segs = cv.LSD(gray);
|
|
1425
|
+
```
|
|
1426
|
+
|
|
1427
|
+
### cornerHarris / cornerSubPix / cornerMinEigenVal / preCornerDetect / spatialGradient
|
|
1428
|
+
|
|
1429
|
+
```typescript
|
|
1430
|
+
function cornerHarris(mat: Mat, options?: { blockSize?: number; ksize?: number; k?: number }): Mat | null;
|
|
1431
|
+
function cornerSubPix(mat: Mat, options: {
|
|
1432
|
+
corners: Point[]; winSize?: Size | [number, number]; zeroZone?: Size | [number, number];
|
|
1433
|
+
criteria?: { type?: number; maxCount?: number; epsilon?: number };
|
|
1434
|
+
}): Point[] | null;
|
|
1435
|
+
function cornerMinEigenVal(mat: Mat, options?: { blockSize?: number; ksize?: number }): Mat | null;
|
|
1436
|
+
function preCornerDetect(mat: Mat, options?: { ksize?: number }): Mat | null;
|
|
1437
|
+
function spatialGradient(mat: Mat, options?: { ksize?: number }): { dx: Mat; dy: Mat } | null;
|
|
1438
|
+
```
|
|
1439
|
+
|
|
1440
|
+
```javascript
|
|
1441
|
+
const corners = cv.goodFeaturesToTrack(gray, { maxCorners: 50, qualityLevel: 0.01, minDistance: 10 });
|
|
1442
|
+
const refined = cv.cornerSubPix(gray, { corners, winSize: [5, 5] });
|
|
1443
|
+
const g = cv.spatialGradient(gray);
|
|
1444
|
+
cv.release(g.dx); cv.release(g.dy);
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
### calcBackProject / applyColorMap / HuMoments / pyrMeanShiftFiltering / integral
|
|
1448
|
+
|
|
1449
|
+
```typescript
|
|
1450
|
+
function calcBackProject(mat: Mat, options: {
|
|
1451
|
+
hist: Mat; channels?: number[]; ranges?: number[]; scale?: number;
|
|
1452
|
+
}): Mat | null;
|
|
1453
|
+
function applyColorMap(mat: Mat, options: { colormap: number }): Mat | null;
|
|
1454
|
+
function HuMoments(contourOrMoments: Point[] | object | Mat): number[] | null;
|
|
1455
|
+
function pyrMeanShiftFiltering(mat: Mat, options?: { sp?: number; sr?: number; maxLevel?: number }): Mat | null;
|
|
1456
|
+
function integral(mat: Mat): Mat | null;
|
|
1457
|
+
```
|
|
1458
|
+
|
|
1459
|
+
```javascript
|
|
1460
|
+
const back = cv.calcBackProject(hsv, { hist, channels: [0], ranges: [0, 180] });
|
|
1461
|
+
const heat = cv.applyColorMap(gray, { colormap: cv.COLORMAP_JET });
|
|
1462
|
+
const hu = cv.HuMoments(contour); // length 7
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
### drawMarker / arrowedLine / fillConvexPoly(就地)
|
|
1466
|
+
|
|
1467
|
+
```typescript
|
|
1468
|
+
function drawMarker(mat: Mat, options: {
|
|
1469
|
+
position: Point; color?: number[] | string;
|
|
1470
|
+
markerType?: number; markerSize?: number; thickness?: number;
|
|
1471
|
+
}): Mat | null;
|
|
1472
|
+
function arrowedLine(mat: Mat, options: {
|
|
1473
|
+
pt1: Point; pt2: Point; color?: number[] | string; thickness?: number; tipLength?: number;
|
|
1474
|
+
}): Mat | null;
|
|
1475
|
+
function fillConvexPoly(mat: Mat, options: { pts: Point[]; color?: number[] | string }): Mat | null;
|
|
1476
|
+
```
|
|
1477
|
+
|
|
1478
|
+
就地修改输入 Mat,返回同一句柄。
|
|
1479
|
+
|
|
1480
|
+
```javascript
|
|
1481
|
+
cv.drawMarker(src, { position: { x: 100, y: 80 }, markerType: cv.MARKER_CROSS });
|
|
1482
|
+
cv.arrowedLine(src, { pt1: { x: 10, y: 10 }, pt2: { x: 200, y: 120 }, color: [0, 0, 255] });
|
|
1483
|
+
cv.fillConvexPoly(src, { pts: [{ x: 10, y: 10 }, { x: 100, y: 20 }, { x: 50, y: 80 }], color: [0, 255, 0] });
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
### connectedComponents / convexityDefects / isContourConvex / fitLine
|
|
1487
|
+
|
|
1488
|
+
```typescript
|
|
1489
|
+
function connectedComponents(mat: Mat, options?: { connectivity?: number }): { count: number; labels: Mat } | null;
|
|
1490
|
+
function convexityDefects(contour: Point[], options: { hull: number[] | Point[] }):
|
|
1491
|
+
Array<{ start: number; end: number; farthest: number; depth: number }> | null;
|
|
1492
|
+
function isContourConvex(contour: Point[]): boolean;
|
|
1493
|
+
function fitLine(points: Point[], options?: {
|
|
1494
|
+
distType?: number; param?: number; reps?: number; aeps?: number;
|
|
1495
|
+
}): [number, number, number, number] | null;
|
|
1496
|
+
```
|
|
1497
|
+
|
|
1498
|
+
`hull` 可为索引数组,或与 `convexHull` 返回格式相同的 Point[]。
|
|
1499
|
+
|
|
1500
|
+
```javascript
|
|
1501
|
+
const cc = cv.connectedComponents(bin, { connectivity: 8 });
|
|
1502
|
+
const hull = cv.convexHull(contour);
|
|
1503
|
+
const defects = cv.convexityDefects(contour, { hull });
|
|
1504
|
+
const line = cv.fitLine(points); // [vx, vy, x0, y0]
|
|
1505
|
+
cv.release(cc.labels);
|
|
1506
|
+
```
|
|
1507
|
+
|
|
1508
|
+
### watershed / grabCut(就地)
|
|
1509
|
+
|
|
1510
|
+
```typescript
|
|
1511
|
+
/** 就地改写 markers,返回 markers 句柄 */
|
|
1512
|
+
function watershed(mat: Mat, options: { markers: Mat }): Mat | null;
|
|
1513
|
+
/** 就地改写 mask,返回 mask 句柄 */
|
|
1514
|
+
function grabCut(mat: Mat, options: {
|
|
1515
|
+
mask: Mat; rect?: Rect; iterCount?: number; mode?: number;
|
|
1516
|
+
}): Mat | null;
|
|
1517
|
+
```
|
|
1518
|
+
|
|
1519
|
+
```javascript
|
|
1520
|
+
cv.watershed(src, { markers }); // 就地改 markers
|
|
1521
|
+
cv.grabCut(src, {
|
|
1522
|
+
mask,
|
|
1523
|
+
rect: { x: 50, y: 50, width: 200, height: 200 },
|
|
1524
|
+
iterCount: 5,
|
|
1525
|
+
mode: cv.GC_INIT_WITH_RECT,
|
|
1526
|
+
}); // 就地改 mask
|
|
1527
|
+
```
|
|
1528
|
+
|
|
1529
|
+
---
|
|
1530
|
+
|
|
1531
|
+
## Calib3d / Features / Objdetect
|
|
1532
|
+
|
|
1533
|
+
### estimateAffine2D / estimateAffinePartial2D
|
|
1534
|
+
|
|
1535
|
+
```typescript
|
|
1536
|
+
function estimateAffine2D(options: {
|
|
1537
|
+
srcPoints: Point[]; dstPoints: Point[]; method?: number; ransacReprojThreshold?: number;
|
|
1538
|
+
}): Mat | null;
|
|
1539
|
+
function estimateAffinePartial2D(options: {
|
|
1540
|
+
srcPoints: Point[]; dstPoints: Point[]; method?: number; ransacReprojThreshold?: number;
|
|
1541
|
+
}): Mat | null;
|
|
1542
|
+
```
|
|
1543
|
+
|
|
1544
|
+
```javascript
|
|
1545
|
+
const M = cv.estimateAffine2D({
|
|
1546
|
+
srcPoints, dstPoints, method: cv.RANSAC, ransacReprojThreshold: 3,
|
|
1547
|
+
});
|
|
1548
|
+
```
|
|
1549
|
+
|
|
1550
|
+
### KAZE / MSER / SimpleBlobDetector / AGAST
|
|
1551
|
+
|
|
1552
|
+
```typescript
|
|
1553
|
+
function KAZE(mat: Mat, options?: { mask?: Mat }): { keypoints: KeyPoint[]; descriptors: Mat | null } | null;
|
|
1554
|
+
function MSER(mat: Mat, options?: { mask?: Mat }): { keypoints: KeyPoint[] } | null;
|
|
1555
|
+
function SimpleBlobDetector(mat: Mat, options?: { mask?: Mat }): { keypoints: KeyPoint[] } | null;
|
|
1556
|
+
function AGAST(mat: Mat, options?: {
|
|
1557
|
+
threshold?: number; nonmaxSuppression?: boolean; mask?: Mat;
|
|
1558
|
+
}): { keypoints: KeyPoint[] } | null;
|
|
1559
|
+
```
|
|
1560
|
+
|
|
1561
|
+
```javascript
|
|
1562
|
+
const kaze = cv.KAZE(gray);
|
|
1563
|
+
const mser = cv.MSER(gray);
|
|
1564
|
+
const blobs = cv.SimpleBlobDetector(gray);
|
|
1565
|
+
const agast = cv.AGAST(gray, { threshold: 10 });
|
|
1566
|
+
if (kaze.descriptors) cv.release(kaze.descriptors);
|
|
1567
|
+
```
|
|
1568
|
+
|
|
1569
|
+
### encodeQRCode / CascadeClassifier / HOGDetect
|
|
1570
|
+
|
|
1571
|
+
```typescript
|
|
1572
|
+
function encodeQRCode(text: string): Mat | null;
|
|
1573
|
+
function CascadeClassifier(mat: Mat, options: {
|
|
1574
|
+
cascadePath?: string; path?: string;
|
|
1575
|
+
scaleFactor?: number; minNeighbors?: number; minSize?: Size | [number, number];
|
|
1576
|
+
}): Rect[] | null;
|
|
1577
|
+
function HOGDetect(mat: Mat, options?: object): Rect[] | null;
|
|
1578
|
+
```
|
|
1579
|
+
|
|
1580
|
+
`CascadeClassifier` 需自行提供 xml 级联路径。
|
|
1581
|
+
|
|
1582
|
+
```javascript
|
|
1583
|
+
const qr = cv.encodeQRCode('https://example.com');
|
|
1584
|
+
const faces = cv.CascadeClassifier(gray, {
|
|
1585
|
+
cascadePath: '/path/to/haarcascade_frontalface_alt.xml',
|
|
1586
|
+
scaleFactor: 1.1,
|
|
1587
|
+
minNeighbors: 3,
|
|
1588
|
+
});
|
|
1589
|
+
const people = cv.HOGDetect(src);
|
|
1590
|
+
cv.release(qr);
|
|
1591
|
+
```
|
|
1592
|
+
|
|
1593
|
+
---
|
|
1594
|
+
|
|
1595
|
+
## 常用常量
|
|
1596
|
+
|
|
1597
|
+
挂在 `cv` 上,例如:
|
|
1598
|
+
|
|
1599
|
+
- 颜色:`COLOR_BGR2GRAY`、`COLOR_RGB2GRAY`、`COLOR_BGR2HSV`、`COLOR_BGR2RGB`、`COLOR_BGRA2BGR`、…
|
|
1600
|
+
- 阈值:`THRESH_BINARY`、`THRESH_BINARY_INV`、`THRESH_OTSU`、`THRESH_TRUNC`、…
|
|
1601
|
+
- 自适应:`ADAPTIVE_THRESH_MEAN_C`、`ADAPTIVE_THRESH_GAUSSIAN_C`
|
|
1602
|
+
- 模板匹配:`TM_SQDIFF`、`TM_CCORR_NORMED`、`TM_CCOEFF_NORMED`、…
|
|
1603
|
+
- 轮廓:`RETR_EXTERNAL`、`RETR_LIST`、`RETR_TREE`、`CHAIN_APPROX_SIMPLE`、…
|
|
1604
|
+
- 形态学:`MORPH_RECT`、`MORPH_OPEN`、`MORPH_CLOSE`、`MORPH_HITMISS`、…
|
|
1605
|
+
- 插值 / 旋转 / 边界:`INTER_*`、`ROTATE_*`、`BORDER_*`
|
|
1606
|
+
- 线型:`LINE_4` / `LINE_8` / `LINE_AA` / `FILLED`
|
|
1607
|
+
- 字体:`FONT_HERSHEY_SIMPLEX`、…
|
|
1608
|
+
- Mat 类型:`CV_8UC1`、`CV_8UC3`、`CV_8UC4`、`CV_32FC1`、`CV_32FC3`
|
|
1609
|
+
- 匹配距离:`NORM_L1`、`NORM_L2`、`NORM_HAMMING`、`NORM_HAMMING2`、`NORM_INF`、`NORM_MINMAX`
|
|
1610
|
+
- 直方图比较:`HISTCMP_CORREL` / `CHISQR` / `INTERSECT` / `BHATTACHARYYA` / …
|
|
1611
|
+
- 单应:`RANSAC`、`LMEDS`、`RHO`
|
|
1612
|
+
- 霍夫:`HOUGH_GRADIENT`、`HOUGH_GRADIENT_ALT`
|
|
1613
|
+
- 距离变换:`DIST_L1`、`DIST_L2`、`DIST_C`、`DIST_MASK_3`、`DIST_MASK_5`
|
|
1614
|
+
- 形状匹配:`CONTOURS_MATCH_I1` / `I2` / `I3`
|
|
1615
|
+
- 连通域统计列:`CC_STAT_LEFT` / `TOP` / `WIDTH` / `HEIGHT` / `AREA`
|
|
1616
|
+
- 读标志:`IMREAD_COLOR`、`IMREAD_GRAYSCALE`、`IMREAD_UNCHANGED`
|
|
1617
|
+
- 修复 / 风格:`INPAINT_NS`、`INPAINT_TELEA`、`RECURS_FILTER`、`NORMCONV_FILTER`
|
|
1618
|
+
- 无缝克隆:`NORMAL_CLONE`、`MIXED_CLONE`、`MONOCHROME_TRANSFER`
|
|
1619
|
+
- 比较:`CMP_EQ` / `CMP_GT` / `CMP_GE` / `CMP_LT` / `CMP_LE` / `CMP_NE`
|
|
1620
|
+
- 伪彩色:`COLORMAP_JET`、`COLORMAP_VIRIDIS`、`COLORMAP_TURBO`、`COLORMAP_HOT`、…
|
|
1621
|
+
- 极坐标:`WARP_POLAR_LINEAR`、`WARP_POLAR_LOG`
|
|
1622
|
+
- 标记:`MARKER_CROSS`、`MARKER_STAR`、`MARKER_DIAMOND`、…
|
|
1623
|
+
- GrabCut:`GC_BGD` / `GC_FGD` / `GC_PR_BGD` / `GC_PR_FGD`、`GC_INIT_WITH_RECT` / `GC_INIT_WITH_MASK` / `GC_EVAL`
|
|
1624
|
+
|
|
1625
|
+
完整列表见类型提示 `types/opencv.d.ts`。
|
|
1626
|
+
|
|
1627
|
+
---
|
|
1628
|
+
|
|
1629
|
+
## 限制与建议
|
|
1630
|
+
|
|
1631
|
+
1. 同时存活的 Mat 句柄有上限(约 32),用完请 `release`,或阶段结束 `releaseAll`;多返回值 API(如 `pencilSketch`、`decolor`、`cartToPolar`)需分别释放。
|
|
1632
|
+
2. 路径 / msbundle / imageId / `screen` 只走 `imread`;其它 API 只接受 Mat 句柄。
|
|
1633
|
+
3. SIFT 描述子优先 `flannKnnMatch`;ORB 用 `BFMatcher` + `NORM_HAMMING`。
|
|
1634
|
+
4. 特征匹配前建议转灰度;大图可先 `pyrDown` / `resize`。
|
|
1635
|
+
5. `findHomography` 至少需要 4 对对应点,不足会返回 `null`。
|
|
1636
|
+
6. 绘制类、`floodFill`、`insertChannel`、`watershed`、`grabCut` 会改原图或指定目标句柄;需保留原图请先 `clone`。
|
|
1637
|
+
7. 与 `image` 互通时,两边句柄各自 `release`。
|
|
1638
|
+
8. `CascadeClassifier` 需要设备上可访问的级联 xml 路径。
|