├── .gitignore
├── assets
├── img
│ ├── amla.jpg
│ └── img.jpg
└── lib
│ └── sgl.js
├── deploy.py
├── 404.html
├── p5js
└── index.html
├── playlist-compare
└── index.html
├── README.zh-CN.md
├── README.md
├── LICENSE
├── demo.html
├── reset.css
├── index.html
├── .github
└── workflows
│ └── pages.yml
├── webgl
├── index.html
├── quadrangle.html
├── dip.html
├── texture.html
├── triangle.html
├── transform.html
├── audio-webgl.html
├── audio-webgl-v3.html
├── video.html
├── audio-webgl-v2.html
└── dip-webgl.html
├── jo
└── a.html
├── ncmdaily
└── index.html
├── lastfm-export
└── index.html
└── dip
├── t.js
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .venv
3 |
--------------------------------------------------------------------------------
/assets/img/amla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldshensheep/toyweb/main/assets/img/amla.jpg
--------------------------------------------------------------------------------
/assets/img/img.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldshensheep/toyweb/main/assets/img/img.jpg
--------------------------------------------------------------------------------
/deploy.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 |
4 | exclude_dirs = ['.github',
5 | '.git', '.idea', 'deploy.py', '.gitignore']
6 |
7 | for root, dirs, files in os.walk('./'):
8 | os.mkdir('dist')
9 | files = set(dirs+files) - set(exclude_dirs)
10 | print(files)
11 | for f in files:
12 | shutil.move(f, 'dist')
13 | break
14 |
--------------------------------------------------------------------------------
/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | My App
5 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/p5js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
12 |
13 |
14 |
15 |
30 |
31 |
--------------------------------------------------------------------------------
/playlist-compare/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 歌单匹配
9 |
10 |
11 |
12 |
16 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | 简体中文
2 |
3 | ## toyweb
4 |
5 | html js 玩具
6 |
7 |
8 | ### [LastFM Export](./lastfm-export) [➡️ 预览](https://oldshensheep.github.io/toyweb/lastfm-export/)
9 |
10 | 导出 last.fm 的数据到 csv.
11 |
12 | ### [Playlist Compare](./playlist-compare)[➡️ 预览](https://oldshensheep.github.io/toyweb/playlist-compare/)
13 |
14 | 网易云音乐和 QQ 音乐的歌单比对。(不完善)
15 |
16 | ### [NCMDaily](./ncmdaily)[➡️ 预览](https://oldshensheep.github.io/toyweb/ncmdaily/)
17 |
18 |
19 | 浏览我的网易云音乐每日推荐。
20 |
21 | ### [Digital Image Processing](./dip) [➡️ 预览](https://oldshensheep.github.io/toyweb/dip/)
22 |
23 | 数字图像处理。纯 javascript。
24 |
25 | - 变成灰度图
26 | - 反转
27 | - 量化
28 | - 高斯滤波器
29 | - 拉普拉斯滤波器
30 | - 最大值滤波器
31 | - ...
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](./README.zh-CN.md)
2 |
3 | ## toyweb
4 |
5 | html js toys
6 |
7 |
8 | ### [LastFM Export](./lastfm-export) [➡️ Preview](https://oldshensheep.github.io/toyweb/lastfm-export/)
9 |
10 | export your last.fm data to csv.
11 |
12 | ### [Playlist Compare](./playlist-compare)[➡️ Preview](https://oldshensheep.github.io/toyweb/playlist-compare/)
13 |
14 | playlist compare for netease cloud music and qqmusic. (incomplete)
15 |
16 | ### [NCMDaily](./ncmdaily)[➡️ Preview](https://oldshensheep.github.io/toyweb/ncmdaily/)
17 |
18 | browse my netease cloud music daily recommendation.
19 |
20 | ### [Digital Image Processing](./dip) [➡️ Preview](https://oldshensheep.github.io/toyweb/dip/)
21 |
22 | digital image processing. pure javascript.
23 |
24 | - grayscale
25 | - invert
26 | - quantify
27 | - gaussian filter
28 | - laplace
29 | - max filter
30 | - ...
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 oldshensheep
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
10 |
11 |
12 |
13 | message:{{ message }}
14 |
15 |
16 |
17 |
18 |
19 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/reset.css:
--------------------------------------------------------------------------------
1 |
2 | html, body, div, span, applet, object, iframe,
3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4 | a, abbr, acronym, address, big, cite, code,
5 | del, dfn, em, img, ins, kbd, q, s, samp,
6 | small, strike, strong, sub, sup, tt, var,
7 | b, u, i, center,
8 | dl, dt, dd, ol, ul, li,
9 | fieldset, form, label, legend,
10 | table, caption, tbody, tfoot, thead, tr, th, td,
11 | article, aside, canvas, details, embed,
12 | figure, figcaption, footer, header, hgroup,
13 | menu, nav, output, ruby, section, summary,
14 | time, mark, audio, video {
15 | margin: 0;
16 | padding: 0;
17 | border: 0;
18 | font-size: 100%;
19 | font: inherit;
20 | vertical-align: baseline;
21 | }
22 | /* HTML5 display-role reset for older browsers */
23 | article, aside, details, figcaption, figure,
24 | footer, header, hgroup, menu, nav, section {
25 | display: block;
26 | }
27 | body {
28 | line-height: 1;
29 | }
30 | ol, ul {
31 | list-style: none;
32 | }
33 | blockquote, q {
34 | quotes: none;
35 | }
36 | blockquote:before, blockquote:after,
37 | q:before, q:after {
38 | content: '';
39 | content: none;
40 | }
41 | table {
42 | border-collapse: collapse;
43 | border-spacing: 0;
44 | }
45 | a{
46 | text-decoration: none;
47 | }
48 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sheep's Toy
8 |
9 |
10 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/.github/workflows/pages.yml:
--------------------------------------------------------------------------------
1 | # Simple workflow for deploying static content to GitHub Pages
2 | name: Deploy static content to Pages
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["main"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow one concurrent deployment
19 | concurrency:
20 | group: "pages"
21 | cancel-in-progress: true
22 |
23 | jobs:
24 | # Single deploy job since we're just deploying
25 | deploy:
26 | environment:
27 | name: github-pages
28 | url: ${{ steps.deployment.outputs.page_url }}
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v3
33 | - run: python3 deploy.py
34 | - name: Setup Pages
35 | uses: actions/configure-pages@v1
36 | - name: Upload artifact
37 | uses: actions/upload-pages-artifact@v1
38 | with:
39 | path: 'dist'
40 | - name: Deploy to GitHub Pages
41 | id: deployment
42 | uses: actions/deploy-pages@main
43 |
--------------------------------------------------------------------------------
/webgl/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | WebGL
11 |
12 |
13 |
14 |
15 | audio-webgl
16 | audio-webgl-v2
17 | audio-webgl-v3
18 |
19 | video-webgl
20 |
21 | Digital image processing(WebGL)
22 | transform
23 | triangle
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/webgl/quadrangle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | webgl2 - triangle
8 |
9 |
10 |
11 |
12 |
13 |
14 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/assets/lib/sgl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * use vertexShaderSource and fragmentShaderSource to init gl
3 | * @param gl {WebGL2RenderingContext}
4 | * @param vertexShaderSource {string}
5 | * @param fragmentShaderSource {string}
6 | * @returns {WebGLProgram}
7 | */
8 | function initShader(gl, vertexShaderSource, fragmentShaderSource) {
9 | let vertexShader = gl.createShader(gl.VERTEX_SHADER);
10 | let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
11 |
12 | gl.shaderSource(vertexShader, vertexShaderSource)
13 | gl.shaderSource(fragmentShader, fragmentShaderSource)
14 |
15 | gl.compileShader(vertexShader);
16 | gl.compileShader(fragmentShader);
17 |
18 | let glProgram = gl.createProgram();
19 |
20 | gl.attachShader(glProgram, vertexShader);
21 | gl.attachShader(glProgram, fragmentShader);
22 |
23 | gl.linkProgram(glProgram);
24 |
25 | gl.useProgram(glProgram);
26 |
27 | return glProgram;
28 | }
29 |
30 | /**
31 | *
32 | * @param gl {WebGL2RenderingContext}
33 | * @param glProgram {WebGLProgram}
34 | * @param bufferData {TypedArray}
35 | * @param type {GLenum}
36 | * @param attributeName {string}
37 | * @param size {number}
38 | * @param normalized {boolean}
39 | * @param drawType {GLenum}
40 | */
41 | function setVertexAttribArray(gl, glProgram, bufferData, type, attributeName, size, normalized, drawType = gl.STATIC_DRAW) {
42 |
43 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
44 | gl.bufferData(gl.ARRAY_BUFFER, bufferData, drawType)
45 |
46 | let attribute = gl.getAttribLocation(glProgram, attributeName);
47 | gl.enableVertexAttribArray(attribute)
48 | gl.vertexAttribPointer(attribute, size, type, normalized, 0, 0)
49 | }
50 |
51 |
52 | /**
53 | *
54 | * @param gl {WebGL2RenderingContext}
55 | * @param glProgram {WebGLProgram}
56 | * @param image {ArrayBufferView}
57 | * @param attributeName {string}
58 | */
59 | function setSampler2D(gl, glProgram, image, attributeName) {
60 | gl.bindTexture(gl.TEXTURE_2D, gl.createTexture())
61 | gl.activeTexture(gl.TEXTURE0);
62 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
63 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
64 | let u_image = gl.getUniformLocation(glProgram, attributeName);
65 | gl.uniform1i(u_image, 0)
66 | }
67 |
--------------------------------------------------------------------------------
/webgl/dip.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Title
8 |
9 |
10 |
15 |
21 |
22 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/webgl/texture.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | webgl2 - triangle
8 |
9 |
10 |
11 |
12 |
13 |
14 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/webgl/triangle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | webgl2 - triangle
8 |
9 |
10 |
11 |
12 |
13 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/webgl/transform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | webgl2 - transform
8 |
9 |
10 |
11 |
If you have a keyboard you can you [WSAD] and [arrow key] to move the parallelogram.
12 |
13 |
14 |
15 |
116 |
117 |
--------------------------------------------------------------------------------
/webgl/audio-webgl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Audio WebGL V1
8 |
9 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/jo/a.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | What?
8 |
19 |
20 |
21 |
65 |
66 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/webgl/audio-webgl-v3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Audio WebGL v3
9 |
10 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/webgl/video.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Title
8 |
9 |
10 |
11 |
19 |
20 |
21 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/ncmdaily/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{currentDate}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/lastfm-export/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | LastFM-Export
18 |
19 |
20 |
21 | get
22 |
23 | Export to CSV File
24 |
25 |
26 |
27 |
28 |
29 | {{Math.ceil(finishedPages/totalPages*100)}}%
30 | ({{finishedPages}}/{{totalPages}})
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/webgl/audio-webgl-v2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Audio WebGL v2
8 |
9 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/dip/t.js:
--------------------------------------------------------------------------------
1 | onmessage = function (msg) {
2 | console.log("Worker: Message received from main script");
3 | console.log(msg.data);
4 | switch (msg.data[0]) {
5 | case "gaussian":
6 | postMessage(gaussian_filter(msg.data[1], msg.data[2], msg.data[3]));
7 | break;
8 | case "uniform":
9 | postMessage(uniform_filter(msg.data[1], msg.data[2]));
10 | break;
11 | case "laplace":
12 | postMessage(laplace(msg.data[1]));
13 | break;
14 | case "sobel":
15 | postMessage(sobel(msg.data[1]));
16 | break;
17 | case "min":
18 | postMessage(sortFilter(msg.data[1], "min", msg.data[2]));
19 | break;
20 | case "med":
21 | postMessage(sortFilter(msg.data[1], "med", msg.data[2]));
22 | break;
23 | case "max":
24 | postMessage(sortFilter(msg.data[1], "max", msg.data[2]));
25 | break;
26 | default:
27 | break;
28 | }
29 | console.log("Worker: Posting message back to main script");
30 | // postMessage(workerResult);
31 | };
32 |
33 | /**
34 | * Turn image to a grayscale image.
35 | * @param {ImageData} imageData
36 | * @returns
37 | */
38 | function grayscale(imageData) {
39 | let newImageData = new ImageData(imageData.width, imageData.height);
40 | let data = imageData.data;
41 | let newData = newImageData.data;
42 | let length = data.length;
43 | for (let i = 0; i < length; i += 4) {
44 | let avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
45 | newData[i] = avg;
46 | newData[i + 1] = avg;
47 | newData[i + 2] = avg;
48 | newData[i + 3] = data[i + 3];
49 | }
50 | return newImageData;
51 | }
52 | /**
53 | * Invert image color.
54 | * @param {ImageData} imageData
55 | * @returns {ImageData}
56 | */
57 | function invert(imageData) {
58 | let newImageData = new ImageData(imageData.width, imageData.height);
59 | let data = imageData.data;
60 | let newData = newImageData.data;
61 | let length = data.length;
62 | for (let i = 0; i < length; i += 4) {
63 | newData[i] = 255 - data[i];
64 | newData[i + 1] = 255 - data[i + 1];
65 | newData[i + 2] = 255 - data[i + 2];
66 | newData[i + 3] = data[i + 3];
67 | }
68 | return newImageData;
69 | }
70 | /**
71 | * Image quantification.
72 | * @param {ImageData} imageData
73 | * @param {Number} q
74 | * @returns
75 | */
76 | function quantify(imageData, q) {
77 | let newImageData = new ImageData(imageData.width, imageData.height);
78 | let data = imageData.data;
79 | let newData = newImageData.data;
80 | let length = data.length;
81 | for (let i = 0; i < length; i += 4) {
82 | newData[i] = Math.floor(data[i] / q) * q;
83 | newData[i + 1] = Math.floor(data[i + 1] / q) * q;
84 | newData[i + 2] = Math.floor(data[i + 2] / q) * q;
85 | newData[i + 3] = data[i + 3];
86 | }
87 | return newImageData;
88 | }
89 | /**
90 | * gaussian filter.
91 | * @param {ImageData} imageData
92 | * @param {Number} sigma the sigma of Math.E ** -(x ** 2 + y ** 2) / (2 * sigma ** 2)
93 | * @param {Number} size the size of the kernel(square).
94 | * @returns
95 | */
96 | function gaussian_filter(imageData, sigma = 2, size = 3) {
97 | let kernel = [];
98 | let kSigma = Math.round(sigma / 2);
99 | for (let i = 0; i < size; i++) {
100 | kernel[i] = [];
101 | for (let j = 0; j < size; j++) {
102 | let x = i - kSigma;
103 | let y = j - kSigma;
104 | kernel[i][j] = Math.E ** (-(x ** 2 + y ** 2) / (2 * sigma ** 2));
105 | }
106 | }
107 | let sum = 0;
108 | for (let i = 0; i < kernel.length; i++) {
109 | for (let j = 0; j < kernel[0].length; j++) {
110 | sum += kernel[i][j];
111 | }
112 | }
113 | for (let i = 0; i < kernel.length; i++) {
114 | for (let j = 0; j < kernel[0].length; j++) {
115 | kernel[i][j] /= sum;
116 | }
117 | }
118 | return conv_imageData(imageData, kernel);
119 | }
120 | /**
121 | * uniform filter.
122 | * @param {ImageData} imageData
123 | * @param {Number} size the size of the kernel(square).
124 | * @returns
125 | */
126 | function uniform_filter(imageData, size = 3) {
127 | kernel = [];
128 | let v = 1 / size / size;
129 | for (let i = 0; i < size; i++) {
130 | kernel[i] = [];
131 | for (let j = 0; j < size; j++) {
132 | kernel[i][j] = v;
133 | }
134 | }
135 | return conv_imageData(imageData, kernel);
136 | }
137 | /**
138 | * laplace.
139 | * @param {ImageData} imageData
140 | * @returns
141 | */
142 | function laplace(imageData) {
143 | kernel = [
144 | [0, -1, 0],
145 | [-1, 4, -1],
146 | [0, -1, 0],
147 | ];
148 | return conv_imageData(imageData, kernel);
149 | }
150 | /**
151 | *
152 | * @param {ImageData} imageData
153 | * @param {Number} axis
154 | * @returns
155 | */
156 | function sobel(imageData, axis = "x") {
157 | let kernel = {
158 | x: [
159 | [-1, -2, -1],
160 | [0, 0, 0],
161 | [1, 2, 1],
162 | ],
163 | y: [
164 | [-1, 0, 1],
165 | [-2, 0, 2],
166 | [-1, 0, 1],
167 | ],
168 | };
169 |
170 | return conv_imageData(imageData, kernel[axis]);
171 | }
172 | /**
173 | * Image convolution.
174 | * @param {ImageData} imageData
175 | * @param {Array} kernel 2D Array
176 | */
177 | function conv_imageData(imageData, kernel) {
178 | let newImageData = new ImageData(imageData.width, imageData.height);
179 | let data = imageData.data;
180 | let newData = newImageData.data;
181 | let iHeight = imageData.height;
182 | let iWidth = imageData.width;
183 | let kRows = kernel.length;
184 | let kCols = kernel[0].length;
185 | let kCenterX = Math.floor(kCols / 2);
186 | let kCenterY = Math.floor(kRows / 2);
187 | for (let i = 0; i < iHeight; i++) {
188 | for (let j = 0; j < iWidth; j++) {
189 | newData[(i * iWidth + j) * 4 + 3] = data[(i * iWidth + j) * 4 + 3];
190 | let a = [0, 0, 0]; // ImageData.data is Uint8ClampedArray
191 | for (let m = 0; m < kRows; m++) {
192 | for (let n = 0; n < kCols; n++) {
193 | let ii = i + (m - kCenterY);
194 | let jj = j + (n - kCenterX);
195 | if (ii >= 0 && ii < iHeight && jj >= 0 && jj < iWidth) {
196 | a[0] += data[(ii * iWidth + jj) * 4 + 0] * kernel[m][n];
197 | a[1] += data[(ii * iWidth + jj) * 4 + 1] * kernel[m][n];
198 | a[2] += data[(ii * iWidth + jj) * 4 + 2] * kernel[m][n];
199 | }
200 | }
201 | }
202 | newData[(i * iWidth + j) * 4 + 0] = a[0];
203 | newData[(i * iWidth + j) * 4 + 1] = a[1];
204 | newData[(i * iWidth + j) * 4 + 2] = a[2];
205 | }
206 | }
207 | return newImageData;
208 | }
209 | /**
210 | *
211 | * @param {ImageData} imageData
212 | * @param {String} p the value of the sorted field.
213 | * @param {Number} size the size of the kernel(square).
214 | * @returns
215 | */
216 | function sortFilter(imageData, p = "min", size = 3) {
217 | let newImageData = new ImageData(imageData.width, imageData.height);
218 | let data = imageData.data;
219 | let newData = newImageData.data;
220 | let iHeight = imageData.height;
221 | let iWidth = imageData.width;
222 | let kRows = size;
223 | let kCols = size;
224 | let kCenterX = Math.floor(size / 2);
225 | let kCenterY = Math.floor(size / 2);
226 | for (let i = 0; i < iHeight; i++) {
227 | for (let j = 0; j < iWidth; j++) {
228 | newData[(i * iWidth + j) * 4 + 3] = data[(i * iWidth + j) * 4 + 3];
229 | let a = [[], [], []]; // ImageData.data is Uint8ClampedArray
230 | for (let m = 0; m < kRows; m++) {
231 | for (let n = 0; n < kCols; n++) {
232 | let ii = i + (m - kCenterY);
233 | let jj = j + (n - kCenterX);
234 | if (ii >= 0 && ii < iHeight && jj >= 0 && jj < iWidth) {
235 | a[0].push(data[(ii * iWidth + jj) * 4 + 0]);
236 | a[1].push(data[(ii * iWidth + jj) * 4 + 1]);
237 | a[2].push(data[(ii * iWidth + jj) * 4 + 2]);
238 | }
239 | }
240 | }
241 | a.forEach((e) => e.sort((a, b) => a - b));
242 | let pos = 0; //最小值
243 | if (p === "max") {
244 | pos = a.length - 1;
245 | } else if (p === "med") {
246 | pos = Math.floor(a.length / 2);
247 | } else if (p === "min") {
248 | pos = 0;
249 | }
250 | newData[(i * iWidth + j) * 4 + 0] = a[0][pos];
251 | newData[(i * iWidth + j) * 4 + 1] = a[1][pos];
252 | newData[(i * iWidth + j) * 4 + 2] = a[2][pos];
253 | }
254 | }
255 | return newImageData;
256 | }
257 | /**
258 | * Turn imageData to an 2D array
259 | * @param {ImageData} imageData
260 | * @returns
261 | */
262 | function imageData2Array(imageData) {
263 | let ia = [];
264 | let iHeight = imageData.height;
265 | let iWidth = imageData.width;
266 | for (let i = 0; i < iWidth; i++) {
267 | ia[i] = [];
268 | for (let j = 0; j < iHeight; j++) {
269 | ia[i][j] = [
270 | data[(j * iWidth + i) * 4 + 0],
271 | data[(j * iWidth + i) * 4 + 1],
272 | data[(j * iWidth + i) * 4 + 2],
273 | data[(j * iWidth + i) * 4 + 3],
274 | ];
275 | }
276 | }
277 | return ia;
278 | }
279 |
--------------------------------------------------------------------------------
/webgl/dip-webgl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
18 |
19 |
20 |
21 |
Js版本
22 |
23 |

29 |
34 |
39 |
{{kernel_name}}
40 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
279 |
280 |
281 |
--------------------------------------------------------------------------------
/dip/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
12 |
16 |
20 | Digital image processing
21 |
22 |
23 |
24 |
25 | WebGL版本
26 |
27 |
36 |
58 |
59 |
60 |
66 |
71 |
72 | {{s}}
73 |
74 |
75 |
76 |
77 | mdi-dots-vertical
78 |
79 |
80 |
81 |
82 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
106 |
107 |
116 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
422 |
423 |
424 |
--------------------------------------------------------------------------------