@mlikiowa/nanaeo 1.0.1703057813356 → 1.0.1704029441834
Sign up to get free protection for your applications and to get access to all the features.
- package/2022/08/04/NewBlog/index.html +1 -1
- package/2022/08/13/GaussWave/index.html +1 -1
- package/2023/12/30/2024/index.html +1 -0
- package/about/index.html +1 -1
- package/archives/2022/08/index.html +1 -1
- package/archives/2022/index.html +1 -1
- package/archives/2023/12/index.html +1 -0
- package/archives/2023/index.html +1 -0
- package/archives/index.html +1 -1
- package/atom.xml +23 -1
- package/categories/DevLog/index.html +1 -1
- package/categories/SiteLog/index.html +1 -1
- package/categories/index.html +1 -1
- package/category/devlog/atom.xml +23 -1
- package/category/devlog/feed.json +11 -0
- package/category/devlog/rss.xml +24 -2
- package/content.json +1 -1
- package/feed.json +11 -0
- package/friends/index.html +1 -1
- package/index.html +1 -1
- package/maps/volantis-sw.js.map +1 -1
- package/package.json +1 -1
- package/rss.xml +24 -2
- package/tag/devlog/atom.xml +23 -1
- package/tag/devlog/feed.json +11 -0
- package/tag/devlog/rss.xml +24 -2
- package/tag/gauss/atom.xml +23 -1
- package/tag/gauss/feed.json +11 -0
- package/tag/gauss/rss.xml +24 -2
- package/tags/DevLog/index.html +1 -1
- package/tags/Gauss/index.html +1 -1
- package/tags/Hexo/index.html +1 -1
- package/tags/HexoThemes/index.html +1 -1
- package/tags/SiteLog/index.html +1 -1
- package/tags/index.html +1 -1
- package/volantis-sw.js +1 -1
package/content.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"meta":{"title":"Village","subtitle":"Mlikiowa Village","description":"It is a little blog~","author":"Mlikiowa","url":"https://nanaeo.cn","root":"/"},"pages":[{"title":"","date":"2023-12-20T07:36:19.537Z","updated":"2023-12-20T07:36:19.537Z","comments":true,"path":"volantis-sw.js","permalink":"https://nanaeo.cn/volantis-sw.js","excerpt":"","text":"// 全站打包上传 npm,sw 并发请求 cdn const prefix = 'volantis-nanaeo'; const cacheSuffixVersion = '00000030-::cacheSuffixVersion::'; const CACHE_NAME = prefix + '-v' + cacheSuffixVersion; const PreCachlist = [ \"/css/style.css\", \"/js/app.js\", \"/js/search/hexo.js\", ]; let NPMMirror = true; const NPMPackage = \"@mlikiowa/nanaeo\"; let NPMPackageVersion = \"1.0.1703042341521\"; let debug = true; // location.hostname == 'localhost' && (debug = true) && (NPMMirror = false); const handleFetch = async (event) => { const url = event.request.url; if (/nocache/.test(url)) { return NetworkOnly(event) } else if (/@latest/.test(url)) { return CacheFirst(event) } else if (/cdnjs\\.cloudflare\\.com/.test(url)) { return CacheAlways(event) } else if (/music\\.126\\.net/.test(url)) { return CacheAlways(event) } else if (/qqmusic\\.qq\\.com/.test(url)) { return CacheAlways(event) } else if (/jsdelivr\\.net/.test(url)) { return CacheAlways(event) } else if (/npm\\.elemecdn\\.com/.test(url)) { return CacheAlways(event) } else if (/unpkg\\.com/.test(url)) { return CacheAlways(event) } else if (/.*\\.(?:png|jpg|jpeg|svg|gif|webp|ico|eot|ttf|woff|woff2|mp3)$/.test(url)) { return CacheAlways(event) } else if (/.*\\.(css|js)$/.test(url)) { return CacheAlways(event) } else { return CacheFirst(event) } } const cdn = { gh: { jsdelivr: 'https://cdn.jsdelivr.net/gh', fastly: 'https://fastly.jsdelivr.net/gh', gcore: 'https://gcore.jsdelivr.net/gh', testingcf: 'https://testingcf.jsdelivr.net/gh', test1: 'https://test1.jsdelivr.net/gh', }, combine: { jsdelivr: 'https://cdn.jsdelivr.net/combine', fastly: 'https://fastly.jsdelivr.net/combine', gcore: 'https://gcore.jsdelivr.net/combine', testingcf: 'https://testingcf.jsdelivr.net/combine', test1: 'https://test1.jsdelivr.net/combine', }, npm: { jsdelivr: 'https://cdn.jsdelivr.net/npm', fastly: 'https://fastly.jsdelivr.net/npm', gcore: 'https://gcore.jsdelivr.net/npm', testingcf: 'https://testingcf.jsdelivr.net/npm', test1: 'https://test1.jsdelivr.net/npm', unpkg: 'https://unpkg.com', eleme: 'https://npm.elemecdn.com', }, cdnjs: { cdnjs: 'https://cdnjs.cloudflare.com/ajax/libs', baomitu: 'https://lib.baomitu.com', bootcdn: 'https://cdn.bootcdn.net/ajax/libs', bytedance: 'https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M', sustech: 'https://mirrors.sustech.edu.cn/cdnjs/ajax/libs', } } const cdn_match_list = [] for (const type in cdn) { for (const key in cdn[type]) { cdn_match_list.push({ type: type, key: cdn[type][key] }) } } const _console = console; const color = { black: '#000000', red: '#FF0000', green: '#008000', yellow: '#FFFF00', blue: '#0000FF', magenta: '#FF00FF', cyan: '#00FFFF', white: '#FFFFFF', }; const add = (...arr) => { let fi = [ [] ]; for (let key = 0; key < arr.length; key++) { const [first, ...other] = arr[key]; fi[0] += first; fi = fi.concat(other); } return fi; }; const createlog = (util) => (...args) => { // const fun = _console[util] ? _console[util] : _console.log; const fun = util == \"error\" ? _console[util] : _console.log; fun.apply(void 0, args); }; const creategroup = (util) => (...args) => { const fun = _console.groupCollapsed; fun.apply(void 0, args); }; const colorUtils = { bold: (str) => { if (typeof str === 'string' || typeof str === 'number') { return `${str};font-weight: bold;`; } for (let key = 1; key < str.length; key++) { str[key] += `;font-weight: bold;`; } return str; } }; const colorHash = { log: 'black', wait: 'cyan', error: 'red', warn: 'yellow', ready: 'green', info: 'blue', event: 'magenta', }; const createChalk = (name) => (...str) => { if (typeof str[0] === 'object') { createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), strArr)); }; const createChalkBg = (name) => (...str) => { if (typeof str[0] === 'object') { createlog(name)(...add(colorUtils.bold(colorUtils[`bg${firstToUpperCase(colorHash[name])}`](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } createlog(name)(...add(colorUtils.bold(colorUtils[`bg${firstToUpperCase(colorHash[name])}`](`[${firstToUpperCase(name)}] `)), strArr)); }; const createChalkGroup = (name) => (...str) => { if (typeof str[0] === 'object') { creategroup(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } creategroup(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), strArr)); }; const chalk = { group: { end: _console.groupEnd }, bg: {} }; Object.keys(colorHash).forEach(key => { chalk[key] = createChalk(key); chalk.group[key] = createChalkGroup(key); chalk.bg[key] = createChalkBg(key); }); const firstToUpperCase = (str) => str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase()); Object.keys(color).forEach(key => { colorUtils[key] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `color:${color[key]}`]; } for (let i = 1; i < str.length; i++) { str[i] += `;color:${color[key]}`; } return str; }; colorUtils[`bg${firstToUpperCase(key)}`] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `padding: 2px 4px; border-radius: 3px; color: ${key === 'white' ? '#000' : '#fff'}; font-weight: bold; background:${color[key]};`]; } for (let i = 1; i < str.length; i++) { str[i] += `;padding: 2px 4px; border-radius: 3px; font-weight: bold; background:${color[key]};`; } return str; }; }); self.logger = { add, ...chalk, ...colorUtils, }; if (!debug) { logger = { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, group: { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, end: () => { }, }, bg: { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, } }; console.log = () => { }; } const generate_uuid = () => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } self.db = { read: (key, config) => { if (!config) { config = { type: \"text\" } } return new Promise((resolve, reject) => { caches.open(CACHE_NAME).then(cache => { cache.match(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`)).then(function (res) { if (!res) resolve(null) res.text().then(text => resolve(text)) }).catch(() => { resolve(null) }) }) }) }, write: (key, value) => { return new Promise((resolve, reject) => { caches.open(CACHE_NAME).then(function (cache) { cache.put(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`), new Response(value)); resolve() }).catch(() => { reject() }) }) } } const compareVersion = (a, b) => { let v1 = a.split('.'); let v2 = b.split('.'); const len = Math.max(v1.length, v2.length); while (v1.length < len) { v1.push('0'); } while (v2.length < len) { v2.push('0'); } for (let i = 0; i < len; i++) { const num1 = parseInt(v1[i]); const num2 = parseInt(v2[i]); if (num1 > num2) { return a; } else if (num1 < num2) { return b; } } return a; } const mirrors = [ `https://registry.npmjs.org/${NPMPackage}/latest`, `https://registry.npmmirror.com/${NPMPackage}/latest`, `https://mirrors.cloud.tencent.com/npm/${NPMPackage}/latest` ] const getLocalVersion = async () => { NPMPackageVersion = await db.read('blog_version') || NPMPackageVersion logger.bg.info(`Local Version: ${NPMPackage}@${NPMPackageVersion}`) } let mirror_time = 0; const setNewestVersion = async () => { if (!NPMMirror) { return } let f = null; if (!(mirror_time % (mirrors.length + 1))) { f = FetchEngine(mirrors); } else { f = fetch(mirrors[(mirror_time % (mirrors.length + 1)) - 1]); } mirror_time++; return f .then(res => res.json()) .then(async res => { if (!res.version) throw ('No Version Found!') NPMPackageVersion = compareVersion(res.version, await db.read('blog_version') || NPMPackageVersion) logger.bg.ready(`${NPMPackage}@${NPMPackageVersion}`) await db.write('blog_version', NPMPackageVersion) }) .catch(error => { logger.error('[Set Newest Version] ' + (error.stack || error)) }) } setInterval(async () => { await setNewestVersion() }, 60 * 1000); setTimeout(async () => { await setNewestVersion() }, 5000) const installFunction = async () => { await getLocalVersion(); return caches.open(CACHE_NAME + \"-precache\") .then(async function (cache) { if (!await db.read('uuid')) { await db.write('uuid', generate_uuid()) } if (PreCachlist.length) { logger.group.event(`Precaching ${PreCachlist.length} files.`); let index = 0; PreCachlist.forEach(function (url) { cache.match(new Request(url)).then(function (response) { if (response) { logger.ready(`Precaching ${url}`); } else { logger.wait(`Precaching ${url}`); cache.add(new Request(url)); } index++; if (index === PreCachlist.length) { logger.ready(`Precached ${PreCachlist.length} files.`); logger.group.end(); } }) }) } }).catch((error) => { logger.error('[install] ' + (error.stack || error)); }) } self.addEventListener('install', async function (event) { logger.bg.event(\"service worker install event listening\"); try { self.skipWaiting(); event.waitUntil(installFunction()); logger.bg.ready('service worker install sucess!'); } catch (error) { logger.error('[install] ' + (error.stack || error)); } }); self.addEventListener('activate', async event => { logger.bg.event(\"service worker activate event listening\"); try { event.waitUntil( caches.keys().then((keys) => { return Promise.all(keys.map((key) => { if (!key.includes(cacheSuffixVersion)) { caches.delete(key); logger.bg.ready('Deleted Outdated Cache: ' + key); } })); }).catch((error) => { logger.error('[activate] ' + (error.stack || error)); }) ); await self.clients.claim() logger.bg.ready('service worker activate sucess!'); } catch (error) { logger.error('[activate] ' + (error.stack || error)); } }) self.addEventListener('fetch', async event => { event.respondWith( handleFetch(event).catch((error) => { logger.error('[fetch] ' + event.request.url + '\\n[error] ' + (error.stack || error)); }) ) }); const NetworkOnly = async (event) => { logger.group.info('NetworkOnly: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) logger.group.end(); return fetch(event.request) } const CacheFirst = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('CacheFirst: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); event.waitUntil(CacheRuntime(event.request)) return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } const CacheAlways = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('CacheAlways: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } const matchCache = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } async function CacheRuntime(request) { const url = new URL(request.url); let response = await matchCDN(request); if (!response) { response = await fetch(request).catch(() => null) } logger.group.event(`Cache Runtime ${url.pathname}`); logger.wait(`Caching url: ${request.url}`); console.log(response); if (request.method === \"GET\" && (url.protocol == \"https:\")) { const cache = await caches.open(CACHE_NAME + \"-runtime\"); cache.put(request, response.clone()).catch(error => { logger.error('[Cache Runtime] ' + (error.stack || error)); if (error.name === 'QuotaExceededError') { caches.delete(CACHE_NAME + \"-runtime\"); logger.ready(\"deleted cache\") } }) logger.ready(`Cached url: ${request.url}`); } else { logger.warn(`Not Cached url: ${request.url}`); } logger.group.end(); return response; } const matchCDN = async (req) => { const nav = navigator const { saveData, effectiveType } = nav.connection || nav.mozConnection || nav.webkitConnection || {} if (saveData || /2g/.test(effectiveType)) { logger.warn(\"Slow Network: Transparent Proxy\"); return fetch(req); } const urls = [] let urlObj = new URL(req.url) let pathType = urlObj.pathname.split('/')[1] let pathTestRes = \"\"; if (NPMMirror && new RegExp(location.origin).test(req.url)) { logger.group.ready(`Match NPM Mirror: ` + req.url); for (const key in cdn.npm) { let url = cdn.npm[key] + \"/\" + NPMPackage + \"@\" + NPMPackageVersion + req.url.replace(location.origin, '') url = fullPath(fullPath(url)) console.log(url); urls.push(url) } logger.group.end() } if (!urls.length) { for (const item of cdn_match_list) { if (new RegExp(item.key).test(req.url)) { pathType = item.type pathTestRes = new RegExp(item.key).exec(req.url)[0] break; } } for (const type in cdn) { if (type === pathType) { logger.group.ready(`Match CDN ${pathType}: ` + req.url); for (const key in cdn[type]) { const url = cdn[type][key] + req.url.replace(pathTestRes, '') console.log(url); urls.push(url) } logger.group.end() } } } let res; if (urls.length) res = FetchEngine(urls) else res = fetch(req) if (res && NPMMirror && new RegExp(location.origin).test(req.url)) { const ext = fullPath(fullPath(req.url)).split('.').pop() const contentType = getContentType(ext) res = res .then(res => res.arrayBuffer()) .then(buffer => new Response(buffer, { headers: { \"Content-Type\": contentType } })) .catch(() => null) } return res } const fullPath = (url) => { url = url.split('?')[0].split('#')[0] if (url.endsWith('/')) { url += 'index.html' } else { const list = url.split('/') const last = list[list.length - 1] if (last.indexOf('.') === -1) { url += '.html' } } return url } async function progress(res) { return new Response(await res.arrayBuffer(), { status: res.status, headers: res.headers }) } function createPromiseAny() { Promise.any = function (promises) { return new Promise((resolve, reject) => { promises = Array.isArray(promises) ? promises : [] let len = promises.length let errs = [] if (len === 0) return reject(new AggregateError('All promises were rejected')) promises.forEach((p) => { if (p instanceof Promise) { p.then( (res) => resolve(res), (err) => { len-- errs.push(err) if (len === 0) reject(new AggregateError(errs)) } ) } else { reject(p) } }) }) } } function fetchAny(reqs) { const controller = new AbortController() return reqs.map(req => { return new Promise((resolve, reject) => { fetch(req, { signal: controller.signal }) .then(progress) .then(res => { controller.abort() if (res.status !== 200) reject(null) else resolve(res) }) .catch(() => reject(null)) }) }) } function fetchParallel(reqs) { const abortEvent = new Event(\"abortOtherInstance\") const eventTarget = new EventTarget(); return reqs.map(async req => { const controller = new AbortController(); let tagged = false; eventTarget.addEventListener(abortEvent.type, () => { if (!tagged) controller.abort(); }) return new Promise((resolve, reject) => { fetch(req, { signal: controller.signal, }).then(res => { tagged = true; eventTarget.dispatchEvent(abortEvent) if (res.status !== 200) reject(null) else resolve(res) }).catch(() => reject(null)) }) }); } const FetchEngine = (reqs) => { if (!Promise.any) createPromiseAny(); return Promise.any(fetchParallel(reqs)).then(res => res) .catch((e) => { if (e == \"AggregateError: All promises were rejected\") { return Promise.any(fetchAny(reqs)) .then((res) => res) .catch(() => null); } return null; }); }; const getContentType = (ext) => { switch (ext) { case 'js': return 'text/javascript' case 'html': return 'text/html' case 'css': return 'text/css' case 'json': return 'application/json' case 'webp': return 'image/webp' case 'jpg': return 'image/jpg' case 'jpeg': return 'image/jpeg' case 'png': return 'image/png' case 'gif': return 'image/gif' case 'xml': return 'text/xml' case 'xsl': return 'text/xml' case 'webmanifest': return 'text/webmanifest' case 'map': return 'application/json' case 'bcmap': return 'image/vnd.wap.wbmp' case 'wbmp': return 'image/vnd.wap.wbmp' case 'bmp': return 'image/bmp' case 'ico': return 'image/vnd.microsoft.icon' case 'tiff': return 'image/tiff' case 'tif': return 'image/tiff' case 'svg': return 'image/svg+xml' case 'svgz': return 'image/svg+xml' case 'woff': return 'application/font-woff' case 'woff2': return 'application/font-woff2' case 'ttf': return 'application/font-ttf' case 'otf': return 'application/font-otf' case 'eot': return 'application/vnd.ms-fontobject' case 'zip': return 'application/zip' case 'tar': return 'application/x-tar' case 'gz': return 'application/gzip' case 'bz2': return 'application/x-bzip2' case 'rar': return 'application/x-rar-compressed' case '7z': return 'application/x-7z-compressed' case 'doc': return 'application/msword' case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' case 'xls': return 'application/vnd.ms-excel' case 'xlsx': return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' case 'ppt': return 'application/vnd.ms-powerpoint' case 'pptx': return 'application/vnd.openxmlformats-officedocument.presentationml.presentation' case 'pdf': return 'application/pdf' case 'txt': return 'text/plain' case 'rtf': return 'application/rtf' case 'mp3': return 'audio/mpeg' case 'wav': return 'audio/x-wav' case 'ogg': return 'audio/ogg' case 'mp4': return 'video/mp4' case 'm4v': return 'video/x-m4v' case 'mov': return 'video/quicktime' case 'avi': return 'video/x-msvideo' case 'wmv': return 'video/x-ms-wmv' case 'flv': return 'video/x-flv' case 'swf': return 'application/x-shockwave-flash' case 'mpg': return 'video/mpeg' case 'mpeg': return 'video/mpeg' case 'mpe': return 'video/mpeg' case 'mpv': return 'video/mpeg' case 'm2v': return 'video/mpeg' case 'm4a': return 'audio/mp4' case 'aac': return 'audio/aac' case 'm3u': return 'audio/x-mpegurl' case 'm3u8': return 'application/vnd.apple.mpegurl' case 'pls': return 'audio/x-scpls' case 'cue': return 'application/x-cue' case 'wma': return 'audio/x-ms-wma' case 'flac': return 'audio/flac' case 'aif': return 'audio/x-aiff' case 'aiff': return 'audio/x-aiff' case 'aifc': return 'audio/x-aiff' case 'au': return 'audio/basic' case 'snd': return 'audio/basic' case 'mid': return 'audio/midi' case 'midi': return 'audio/midi' case 'kar': return 'audio/midi' default: return 'text/plain' } }"},{"title":"","date":"2023-12-20T07:36:19.525Z","updated":"2023-12-20T07:36:19.525Z","comments":true,"path":"about/index.html","permalink":"https://nanaeo.cn/about/index.html","excerpt":"","text":"Hi, I’m Mlikiowa!是一位正在创作与做出改变的大学生,正在思考着知识与生活,并且为此刻而庆幸着… ExpPrevious 与Ghost在System游玩,Win酱还是Win7的样子。 2015 在Win10萌芽的时代,遇见CoolQ后咱变成了一位开发者. 2016 时间过去一年,我知道我不会一直待在这个圈子里面,于是很快我直接脱离了Plugins的开发,开始开发桌面软件,并尝试着运营,结果是必然失败的,年纪 经济 技术都在限制着发挥。 2017 在这个年份,基于TencentQQ 和 Http1.1的协议研究,对我影响巨大,借此契机我学习了大量前端知识(IE tester甚至还可以运行),贴吧火热的年代总是牛人出没,因此我同年参与大型IM设计,负责部分协议的完成。 2018 前端知识基础之上缺少web开发使我迫切的接触了PHP,同时补习了CPP开发经验,并开发桌面动态壁纸项目等较成熟项目 2019 在初中毕业前的学习到此为止,我那一年开始写博客,并且了解WEB渗透知识 2020 高中忙忙碌碌的自己,完成了某网站的项目,Linux开始频繁出现在我的眼前这一年对图形编程有所提高,审美提高,但是核心技术部分未有较大突破。 2021 这年因高中学业为主,是站长的生活而非一个有理想的开发者,severless等新技术出现在眼前告诉着我众多新技术诞生,我开始尝试各种新技术新方案巨大的收获是开始活跃于开源平台. 2022 学习Python与Nodejs"},{"title":"所有分类","date":"2023-12-20T07:36:19.537Z","updated":"2023-12-20T07:36:19.537Z","comments":true,"path":"categories/index.html","permalink":"https://nanaeo.cn/categories/index.html","excerpt":"","text":""},{"title":"我的朋友们","date":"2023-12-20T07:36:19.537Z","updated":"2023-12-20T07:36:19.537Z","comments":true,"path":"friends/index.html","permalink":"https://nanaeo.cn/friends/index.html","excerpt":"My Friends","text":"My Friends 友情链接自助申请https://github.com/MliKiowa/BlogFriend MySite 12345Name:Mlikiowa Home Villagedescription:A little Village With MlikiowaUrl:https://nanaeo.cn/avatar(100x100):https://q1.qlogo.cn/g?b=qq&nk=1627126029&s=100siteshot:"},{"title":"所有标签","date":"2023-12-20T07:36:19.537Z","updated":"2023-12-20T07:36:19.537Z","comments":true,"path":"tags/index.html","permalink":"https://nanaeo.cn/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"高斯滤波","slug":"GaussWave","date":"2022-08-13T16:00:00.000Z","updated":"2023-12-20T07:36:19.525Z","comments":true,"path":"2022/08/13/GaussWave/","link":"","permalink":"https://nanaeo.cn/2022/08/13/GaussWave/","excerpt":"高斯滤波的实现","text":"高斯滤波的实现 本文提示本文提供了相关代码和算法仅为示例学习,并非标准案例,并且OpenCV提供了高斯滤波函数,如果遇到不明白的概念和地方可以参考引用文章理解,也可以尝试在搜索引擎上搜索相关概念和图片示例,由于本站资源原因,暂不提供图片。 tips: 本文为了方便仅是灰度图片处理如果需要彩色图片应该尝试修改代码三种通道进行分别处理或其它方法。 概念理解(部分来自百科等)滤波滤波就对图像像素点及其邻域点的灰度值按照一定的参数规则进行加权平均,可以有效滤去理想图像中叠加的高频噪声。常用的滤波有线性滤波、中值滤波、均值滤波、双边滤波、高斯滤波等。滤波有抑制噪声的作用,但这会使得图像边缘模糊。(摘自别的地方) 低通滤波低通滤波是一种过滤方式,规则为低频信号能正常通过,而超过设定临界值的高频信号则被阻隔、减弱,图像处理领域可用来模糊。 高通滤波高通滤波(high-pass filter) 是一种过滤方式,规则为高频信号能正常通过,而低于设定临界值的低频信号则被阻隔、减弱。但是阻隔、减弱的幅度则会依据不同的频率以及不同的滤波程序(目的)而改变,图像处理领域可用于锐化。 高斯滤波高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程,对处理呈现正态分布(高斯分布)的噪声(包括图像噪声)效果显著。tips: 常用高斯模糊就是使用高斯滤波完成的, 高斯模糊是低通滤波的一种, 也就是滤波函数是低通高斯函数, 但是高斯滤波是指用高斯函数作为滤波函数, 至于是不是模糊,要看是高斯低通还是高斯高通, 低通就是模糊, 高通就是锐化。 核算子、模板、结构都是一种当我们进行图像处理时时,使用到的权用一个矩阵表示,可以利用该矩阵计算对应像素,同时我们叫这个矩阵为核算子、模板、结构。(示例见前提指明)大小可小可大,并且一般为奇数,Que:核大小为什么是都是类似3×3/5×5 奇数呢?其中一个原因是定位中心锚点,偶数是无法确定中心点的。 滤波核当进行滤波时,里面是核的内容是权重并且可以用于处理像素,那么该核称为滤波核。(通俗解释 专业解释 请查询资料) 归一化就是生成核或者说模板加起来的权不为一,这时候我们核内每一个值除以核内总值,就实现了归一化。 卷积核如果一个核被用于卷积那么该核也可以被称为卷积核。(通俗解释 专业解释 请查询资料) 高斯核那么高斯核固然就是高斯分布生成的核了 环境与依赖Python 本次使用的编程语言OpenCV 跨平台计算机视觉库Windows11 本文中代码运行系统 OpenCv库安装(清华源 可自行切换) 12pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-pythonpip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python 举例最终滤波核示例 (提示:权请保证和为1 此处已经归一化 但并非真实情况)0.1 0.1 0.20.1 0.1 0.10.1 0.1 0.1 为3×3网格坐标结构该模板大小 3×3 算法过程高斯滤波实现方法看完以上相信各位并没有很多理解,并不要紧,联系实际我们进一步进行高斯滤波通常情况下有两种实现方式,一是用离散化窗口滑窗卷积, 另一种通过傅里叶变换,其中第一种毕竟常见,可能这时候有人又问了,这又是什么,别急,咱先慢慢来,离散化窗口滑窗卷积其实就是进行有限次的移动核运算区域的卷积运算,那么我们可以开始了。 算法过程0.图像灰度处理 (为了方便) 生成滤波核 进行卷积处理图像 生成滤波核(此处为一维高斯函数) sigma 为标准差 图像平滑程度取决于该值我们使用高斯函数进行生成对应滤波核离中心点越远那么边缘值的权值越小,我们依照高斯二维函数就可以生成对应滤波核。代码具体参考如下 123456789def GaussKernel(size,k,sigma): _t = np.zeros((size,size),np.float32) for i in range (size): for j in range (size): norm = math.pow(i-k,2) + pow(j-k,2) _t[i,j] = math.exp(-norm/(2*math.pow(sigma,2)))/2*math.pi*pow(sigma,2) sum = np.sum(_t) kernel = _t/sum return kernel 卷积生成然后我们使用对应的滤波权值进行乘以像素值,就可以生成新值,但是滤波核仅3×3大小,我们在原图像每一个像素点运算一次,即可生成新的图形。运算为: 每个像素点周围点 权×值 的和为中心点新值。 1234567891011def mygaussFilter(img_gray,kernel): h,w = img_gray.shape k_h,k_w = kernel.shape for i in range(int(k_h/2),h-int(k_h/2)): for j in range(int(k_h/2),w-int(k_h/2)): sum = 0 for k in range(0,k_h): for l in range(0,k_h): sum += img_gray[i-int(k_h/2)+k,j-int(k_h/2)+l]*kernel[k,l] img_gray[i,j] = sum return img_gray 样例代码1234567891011121314151617181920212223242526272829303132333435363738394041import mathimport cv2import numpy as npdef GaussKernel(size,k,sigma): _t = np.zeros((size,size),np.float32) for i in range (size): for j in range (size): norm = math.pow(i-k,2) + pow(j-k,2) _t[i,j] = math.exp(-norm/(2*math.pow(sigma,2)))/2*math.pi*pow(sigma,2) sum = np.sum(_t) kernel = _t/sum return kerneldef mygaussFilter(img_gray,kernel): h,w = img_gray.shape k_h,k_w = kernel.shape for i in range(int(k_h/2),h-int(k_h/2)): for j in range(int(k_h/2),w-int(k_h/2)): sum = 0 for k in range(0,k_h): for l in range(0,k_h): sum += img_gray[i-int(k_h/2)+k,j-int(k_h/2)+l]*kernel[k,l] img_gray[i,j] = sum return img_grayif __name__ == '__main__': img = cv2.imread("demo.jpg") img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) img_g = img_gray.copy() k=1 size = 2*k+1 kernel = gausskernel(size,k,1.5) print(kernel) img_B,img_G,img_R = cv2.split(img) img_gauss_B = mygaussFilter(img_B,kernel) img_gauss_G = mygaussFilter(img_G,kernel) img_gauss_R = mygaussFilter(img_R,kernel) img_gauss = cv2.merge([img_gauss_B,img_gauss_G,img_gauss_R]) img_comp = np.hstack((img,img_gauss)) cv2.imshow("gauss",img_comp) cv2.waitKey(0) 直接OpenCV操作(非原理实现方案 使用封装方法)1234567import cv2Gn=cv2.imread("Gaussian_noise.jpg") Gf=cv2.GaussianBlur(Gn,(3,3),0,0)cv2.imshow("噪声图像",Gn)cv2.imshow("滤波图像",Gf)cv2.waitKey()cv2.destroyAllWindows() Que: 边界点的处理如果一个点处于边界,周边没有足够的点,怎么办?一个变通方法,就是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。当然我们这里很简单,就是进行矩阵补零上去,用零进行模拟完整矩阵。 总结高斯滤波可以让图像高斯噪声降低,并且平滑图像,并且opencv等库已经提供封装,我们可以很快的使用 文章引用高斯滤波https://blog.csdn.net/weixin_51571728/article/details/121527964高斯滤波核https://blog.csdn.net/qqq777_/article/details/112800310有关线性滤波、滤波核的基本概念(概念理解)https://blog.csdn.net/weixin_42664622/article/details/103672899数字图像处理基础 — 高斯滤波https://zhuanlan.zhihu.com/p/82569305图像滤波原理(不推荐)https://view.inews.qq.com/a/20220425A06HHF00 提示该文章并不准确,如果有错误请积极指出。","categories":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/categories/DevLog/"}],"tags":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/tags/DevLog/"},{"name":"Gauss","slug":"Gauss","permalink":"https://nanaeo.cn/tags/Gauss/"}]},{"title":"新博客建好啦","slug":"NewBlog","date":"2022-08-04T16:00:00.000Z","updated":"2023-12-20T07:36:19.525Z","comments":true,"path":"2022/08/04/NewBlog/","link":"","permalink":"https://nanaeo.cn/2022/08/04/NewBlog/","excerpt":"Hi Hexo,I am Mlikiowa!是全新的Hexo/vlolantis博客,我又回来写博客了!","text":"Hi Hexo,I am Mlikiowa!是全新的Hexo/vlolantis博客,我又回来写博客了! 回忆2019.Previous 使用过Emlog Wordpress来搭建博客,使用过各种博客系统,体验不能说差,只能说没有。 2019.Done 开始尝试在CSDN 简书平台发布自己的文章,但是后来因为咱不太喜欢平台限制,遂转入Typecho来搭建博客。 2020.Done 一开始typecho小而美的感觉是很不错的体验,加上我正好会使用PHP,能自己搓插件,所以体验还不错。 2021.Done 期间域名备案和准备高考,并搭建了一个运行在国内的typecho博客。 2022.Done 上半年:因为没有空闲时间打理博客,备案因无法联系注销,后来意外将电脑中typecho的备份删除,故跑路。下半年:借大佬之手找回了数据,但准备重新开始,于是依靠Hexo搭建了全新的博客,走上了白嫖之路。 事件前言: 各位好啊,以上就是我的悲剧经历了,现在我又新搭了博客,使用Hexo博客来进行搭建,依托serverless和action等工具实现。 备案悲剧: 之前我一直使用typecho,服务器和域名在国内备案,高中学业繁忙,每天都忙着学习。所以个人就没有时间处理相关的事情,审核电话我也没有接到,导致国内备案掉了,加上本来博文写的就不怎么样,后来干脆就直接删掉跑路了,虽然后面通过大佬进行找回了,我也是决定从头开始了。 计划上线: 直到2022年的下半年毕业,我终于想起时修理博客,却又嫌折腾博客麻烦,国内备案审核挺烦。本来是计划在另一位大佬那里使用Typecho搭建博客,因为typecho某些地方有些实在是难受,导致我实在是忍受不了痛苦了(恼,于是很快决定更换博客系统。 实际行动: 于是我决定博客使用hexo搭建,并且以低成本实现搭个稳定的博客,本博客是非常容易在新设备上使用,轻松可以在新的地方迁移使用,将跑路可能性降到最低了。 博客运行环境 Name Content Blog Hexo Theme volantis platform vercel&Github domain nanaeo.cn 小吐槽: 之前还想试试hexo-theme-diaspora这样的主题,这款博客是从wp移植到hexo的,介绍图很好看,可惜作者没更新了,于是我只能选择其它主题了。所以我换成了volantis主题 (npm -i hexo-theme-volantis 可以轻松安装),个人感觉色调和布局都很好看,可玩程度很高。 博客搭建本博客源码项目https://github.com/MliKiowa/MliKiowa.github.io 本博客通过使用GithubAction等方式生成部署分发博文到如githubpage vercel等服务商至于推送到cos/oss .etc storage bucket还是算了,毕竟谁用谁欠费(容易挨打,好点情况也得宕了)。 小提示: 使用多服务商涉及到Dns分流,像腾讯Dnspod的这种解析服务要交钱升级才能使用,非常的难受,所以我考虑使用动态Api进行切换dns解析。 小吐槽: 居然github workflow只有已经写好的deploy hugo site to githubpage workflow,没有hexo自动部署的脚步,于是我照猫画虎写了一个Hexo自动部署脚本,但因水平太菜,用这个workflow还得我改了半天。正当我吐槽这么大个github没人发布自动部署脚本的时候,我在github search找到了类似的workflow,但是我已经写完了,难受。 迁移使用 本博客通过以下脚本可以快速迁移,从云端Github下载源码然后在本地进行编写博文,提交后直接在使用action刷新博客。 (该内容已经失效) Tips: 如果你有需要也可以执行以下脚本建立新博客,可以轻松在新设备上运行。 bash.sh 1234git clone https://github.com/MliKiowa/nanaeocd MliKiowa.github.ionpm installhexo g 博客内容 Classification Content Dev Exp Free Developer Site Log Site Maintenance Log Life Log Record your life 小提示: 内容的主要以编程和生活为主,不会有资源推荐,也不接受类似站点友链。 期盼 域名问题: 原来的域名看起来好憨,还被我朋友嘲笑了,因此旧域名怎么能配得上新博客,所以我还是注册个符合气质的新域名啊,所以nanaeo.cn诞生了,寓意没有很特别,全凭感觉来,可爱就对了不是嘛(歪头 跑路问题: 折腾数次各种博客的我真的是太累了,所以本博客能run起来我觉得不是不会去折腾什么新博客了,但是请允许我说一句,我正在努力成为年更博主吧,半年一更就是高产! 内容布局: 咱正在正在摸索,你现在看到的排版全是我正在尝试的,我很少使用Hexo,可以说是全新的萌新,但是让我来慢慢完善应该没有任何问题。 图床问题: 这个问题我根本不知道怎么解决我还是摆烂吧,博文能不放图我绝对不会放图出来。 总结一下: 这就是Mlikiowa全新的博客了,Always believe that something wonderful is about to happen.Let’s go!","categories":[{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/categories/SiteLog/"}],"tags":[{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/tags/SiteLog/"},{"name":"HexoThemes","slug":"HexoThemes","permalink":"https://nanaeo.cn/tags/HexoThemes/"},{"name":"Hexo","slug":"Hexo","permalink":"https://nanaeo.cn/tags/Hexo/"}]}],"categories":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/categories/DevLog/"},{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/categories/SiteLog/"}],"tags":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/tags/DevLog/"},{"name":"Gauss","slug":"Gauss","permalink":"https://nanaeo.cn/tags/Gauss/"},{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/tags/SiteLog/"},{"name":"HexoThemes","slug":"HexoThemes","permalink":"https://nanaeo.cn/tags/HexoThemes/"},{"name":"Hexo","slug":"Hexo","permalink":"https://nanaeo.cn/tags/Hexo/"}]}
|
1
|
+
{"meta":{"title":"Village","subtitle":"Mlikiowa Village","description":"It is a little blog~","author":"Mlikiowa","url":"https://nanaeo.cn","root":"/"},"pages":[{"title":"","date":"2023-12-31T13:30:05.752Z","updated":"2023-12-31T13:30:05.752Z","comments":true,"path":"volantis-sw.js","permalink":"https://nanaeo.cn/volantis-sw.js","excerpt":"","text":"// 全站打包上传 npm,sw 并发请求 cdn const prefix = 'volantis-nanaeo'; const cacheSuffixVersion = '00000031-::cacheSuffixVersion::'; const CACHE_NAME = prefix + '-v' + cacheSuffixVersion; const PreCachlist = [ \"/css/style.css\", \"/js/app.js\", \"/js/search/hexo.js\", ]; let NPMMirror = true; const NPMPackage = \"@mlikiowa/nanaeo\"; let NPMPackageVersion = \"1.0.1703057813356\"; let debug = true; // location.hostname == 'localhost' && (debug = true) && (NPMMirror = false); const handleFetch = async (event) => { const url = event.request.url; if (/nocache/.test(url)) { return NetworkOnly(event) } else if (/@latest/.test(url)) { return CacheFirst(event) } else if (/cdnjs\\.cloudflare\\.com/.test(url)) { return CacheAlways(event) } else if (/music\\.126\\.net/.test(url)) { return CacheAlways(event) } else if (/qqmusic\\.qq\\.com/.test(url)) { return CacheAlways(event) } else if (/jsdelivr\\.net/.test(url)) { return CacheAlways(event) } else if (/npm\\.elemecdn\\.com/.test(url)) { return CacheAlways(event) } else if (/unpkg\\.com/.test(url)) { return CacheAlways(event) } else if (/.*\\.(?:png|jpg|jpeg|svg|gif|webp|ico|eot|ttf|woff|woff2|mp3)$/.test(url)) { return CacheAlways(event) } else if (/.*\\.(css|js)$/.test(url)) { return CacheAlways(event) } else { return CacheFirst(event) } } const cdn = { gh: { jsdelivr: 'https://cdn.jsdelivr.net/gh', fastly: 'https://fastly.jsdelivr.net/gh', gcore: 'https://gcore.jsdelivr.net/gh', testingcf: 'https://testingcf.jsdelivr.net/gh', test1: 'https://test1.jsdelivr.net/gh', }, combine: { jsdelivr: 'https://cdn.jsdelivr.net/combine', fastly: 'https://fastly.jsdelivr.net/combine', gcore: 'https://gcore.jsdelivr.net/combine', testingcf: 'https://testingcf.jsdelivr.net/combine', test1: 'https://test1.jsdelivr.net/combine', }, npm: { jsdelivr: 'https://cdn.jsdelivr.net/npm', fastly: 'https://fastly.jsdelivr.net/npm', gcore: 'https://gcore.jsdelivr.net/npm', testingcf: 'https://testingcf.jsdelivr.net/npm', test1: 'https://test1.jsdelivr.net/npm', unpkg: 'https://unpkg.com', eleme: 'https://npm.elemecdn.com', }, cdnjs: { cdnjs: 'https://cdnjs.cloudflare.com/ajax/libs', baomitu: 'https://lib.baomitu.com', bootcdn: 'https://cdn.bootcdn.net/ajax/libs', bytedance: 'https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M', sustech: 'https://mirrors.sustech.edu.cn/cdnjs/ajax/libs', } } const cdn_match_list = [] for (const type in cdn) { for (const key in cdn[type]) { cdn_match_list.push({ type: type, key: cdn[type][key] }) } } const _console = console; const color = { black: '#000000', red: '#FF0000', green: '#008000', yellow: '#FFFF00', blue: '#0000FF', magenta: '#FF00FF', cyan: '#00FFFF', white: '#FFFFFF', }; const add = (...arr) => { let fi = [ [] ]; for (let key = 0; key < arr.length; key++) { const [first, ...other] = arr[key]; fi[0] += first; fi = fi.concat(other); } return fi; }; const createlog = (util) => (...args) => { // const fun = _console[util] ? _console[util] : _console.log; const fun = util == \"error\" ? _console[util] : _console.log; fun.apply(void 0, args); }; const creategroup = (util) => (...args) => { const fun = _console.groupCollapsed; fun.apply(void 0, args); }; const colorUtils = { bold: (str) => { if (typeof str === 'string' || typeof str === 'number') { return `${str};font-weight: bold;`; } for (let key = 1; key < str.length; key++) { str[key] += `;font-weight: bold;`; } return str; } }; const colorHash = { log: 'black', wait: 'cyan', error: 'red', warn: 'yellow', ready: 'green', info: 'blue', event: 'magenta', }; const createChalk = (name) => (...str) => { if (typeof str[0] === 'object') { createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } createlog(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), strArr)); }; const createChalkBg = (name) => (...str) => { if (typeof str[0] === 'object') { createlog(name)(...add(colorUtils.bold(colorUtils[`bg${firstToUpperCase(colorHash[name])}`](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } createlog(name)(...add(colorUtils.bold(colorUtils[`bg${firstToUpperCase(colorHash[name])}`](`[${firstToUpperCase(name)}] `)), strArr)); }; const createChalkGroup = (name) => (...str) => { if (typeof str[0] === 'object') { creategroup(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), ...str)); return; } let strArr = str; if (typeof str === 'string' || typeof str === 'number') { strArr = colorUtils[colorHash[name]](str); } creategroup(name)(...add(colorUtils.bold(colorUtils[colorHash[name]](`[${firstToUpperCase(name)}] `)), strArr)); }; const chalk = { group: { end: _console.groupEnd }, bg: {} }; Object.keys(colorHash).forEach(key => { chalk[key] = createChalk(key); chalk.group[key] = createChalkGroup(key); chalk.bg[key] = createChalkBg(key); }); const firstToUpperCase = (str) => str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase()); Object.keys(color).forEach(key => { colorUtils[key] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `color:${color[key]}`]; } for (let i = 1; i < str.length; i++) { str[i] += `;color:${color[key]}`; } return str; }; colorUtils[`bg${firstToUpperCase(key)}`] = (str) => { if (typeof str === 'string' || typeof str === 'number') { return [`%c${str}`, `padding: 2px 4px; border-radius: 3px; color: ${key === 'white' ? '#000' : '#fff'}; font-weight: bold; background:${color[key]};`]; } for (let i = 1; i < str.length; i++) { str[i] += `;padding: 2px 4px; border-radius: 3px; font-weight: bold; background:${color[key]};`; } return str; }; }); self.logger = { add, ...chalk, ...colorUtils, }; if (!debug) { logger = { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, group: { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, end: () => { }, }, bg: { log: () => { }, wait: () => { }, error: () => { }, warn: () => { }, ready: () => { }, info: () => { }, event: () => { }, } }; console.log = () => { }; } const generate_uuid = () => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } self.db = { read: (key, config) => { if (!config) { config = { type: \"text\" } } return new Promise((resolve, reject) => { caches.open(CACHE_NAME).then(cache => { cache.match(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`)).then(function (res) { if (!res) resolve(null) res.text().then(text => resolve(text)) }).catch(() => { resolve(null) }) }) }) }, write: (key, value) => { return new Promise((resolve, reject) => { caches.open(CACHE_NAME).then(function (cache) { cache.put(new Request(`https://LOCALCACHE/${encodeURIComponent(key)}`), new Response(value)); resolve() }).catch(() => { reject() }) }) } } const compareVersion = (a, b) => { let v1 = a.split('.'); let v2 = b.split('.'); const len = Math.max(v1.length, v2.length); while (v1.length < len) { v1.push('0'); } while (v2.length < len) { v2.push('0'); } for (let i = 0; i < len; i++) { const num1 = parseInt(v1[i]); const num2 = parseInt(v2[i]); if (num1 > num2) { return a; } else if (num1 < num2) { return b; } } return a; } const mirrors = [ `https://registry.npmjs.org/${NPMPackage}/latest`, `https://registry.npmmirror.com/${NPMPackage}/latest`, `https://mirrors.cloud.tencent.com/npm/${NPMPackage}/latest` ] const getLocalVersion = async () => { NPMPackageVersion = await db.read('blog_version') || NPMPackageVersion logger.bg.info(`Local Version: ${NPMPackage}@${NPMPackageVersion}`) } let mirror_time = 0; const setNewestVersion = async () => { if (!NPMMirror) { return } let f = null; if (!(mirror_time % (mirrors.length + 1))) { f = FetchEngine(mirrors); } else { f = fetch(mirrors[(mirror_time % (mirrors.length + 1)) - 1]); } mirror_time++; return f .then(res => res.json()) .then(async res => { if (!res.version) throw ('No Version Found!') NPMPackageVersion = compareVersion(res.version, await db.read('blog_version') || NPMPackageVersion) logger.bg.ready(`${NPMPackage}@${NPMPackageVersion}`) await db.write('blog_version', NPMPackageVersion) }) .catch(error => { logger.error('[Set Newest Version] ' + (error.stack || error)) }) } setInterval(async () => { await setNewestVersion() }, 60 * 1000); setTimeout(async () => { await setNewestVersion() }, 5000) const installFunction = async () => { await getLocalVersion(); return caches.open(CACHE_NAME + \"-precache\") .then(async function (cache) { if (!await db.read('uuid')) { await db.write('uuid', generate_uuid()) } if (PreCachlist.length) { logger.group.event(`Precaching ${PreCachlist.length} files.`); let index = 0; PreCachlist.forEach(function (url) { cache.match(new Request(url)).then(function (response) { if (response) { logger.ready(`Precaching ${url}`); } else { logger.wait(`Precaching ${url}`); cache.add(new Request(url)); } index++; if (index === PreCachlist.length) { logger.ready(`Precached ${PreCachlist.length} files.`); logger.group.end(); } }) }) } }).catch((error) => { logger.error('[install] ' + (error.stack || error)); }) } self.addEventListener('install', async function (event) { logger.bg.event(\"service worker install event listening\"); try { self.skipWaiting(); event.waitUntil(installFunction()); logger.bg.ready('service worker install sucess!'); } catch (error) { logger.error('[install] ' + (error.stack || error)); } }); self.addEventListener('activate', async event => { logger.bg.event(\"service worker activate event listening\"); try { event.waitUntil( caches.keys().then((keys) => { return Promise.all(keys.map((key) => { if (!key.includes(cacheSuffixVersion)) { caches.delete(key); logger.bg.ready('Deleted Outdated Cache: ' + key); } })); }).catch((error) => { logger.error('[activate] ' + (error.stack || error)); }) ); await self.clients.claim() logger.bg.ready('service worker activate sucess!'); } catch (error) { logger.error('[activate] ' + (error.stack || error)); } }) self.addEventListener('fetch', async event => { event.respondWith( handleFetch(event).catch((error) => { logger.error('[fetch] ' + event.request.url + '\\n[error] ' + (error.stack || error)); }) ) }); const NetworkOnly = async (event) => { logger.group.info('NetworkOnly: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) logger.group.end(); return fetch(event.request) } const CacheFirst = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('CacheFirst: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); event.waitUntil(CacheRuntime(event.request)) return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } const CacheAlways = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('CacheAlways: ' + new URL(event.request.url).pathname); logger.wait('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } const matchCache = async (event) => { return caches.match(event.request).then(function (resp) { logger.group.info('service worker fetch: ' + event.request.url) if (resp) { logger.group.ready(`Cache Hit`); console.log(resp) logger.group.end(); logger.group.end(); return resp; } else { logger.warn(`Cache Miss`); logger.group.end(); return CacheRuntime(event.request) } }) } async function CacheRuntime(request) { const url = new URL(request.url); let response = await matchCDN(request); if (!response) { response = await fetch(request).catch(() => null) } logger.group.event(`Cache Runtime ${url.pathname}`); logger.wait(`Caching url: ${request.url}`); console.log(response); if (request.method === \"GET\" && (url.protocol == \"https:\")) { const cache = await caches.open(CACHE_NAME + \"-runtime\"); cache.put(request, response.clone()).catch(error => { logger.error('[Cache Runtime] ' + (error.stack || error)); if (error.name === 'QuotaExceededError') { caches.delete(CACHE_NAME + \"-runtime\"); logger.ready(\"deleted cache\") } }) logger.ready(`Cached url: ${request.url}`); } else { logger.warn(`Not Cached url: ${request.url}`); } logger.group.end(); return response; } const matchCDN = async (req) => { const nav = navigator const { saveData, effectiveType } = nav.connection || nav.mozConnection || nav.webkitConnection || {} if (saveData || /2g/.test(effectiveType)) { logger.warn(\"Slow Network: Transparent Proxy\"); return fetch(req); } const urls = [] let urlObj = new URL(req.url) let pathType = urlObj.pathname.split('/')[1] let pathTestRes = \"\"; if (NPMMirror && new RegExp(location.origin).test(req.url)) { logger.group.ready(`Match NPM Mirror: ` + req.url); for (const key in cdn.npm) { let url = cdn.npm[key] + \"/\" + NPMPackage + \"@\" + NPMPackageVersion + req.url.replace(location.origin, '') url = fullPath(fullPath(url)) console.log(url); urls.push(url) } logger.group.end() } if (!urls.length) { for (const item of cdn_match_list) { if (new RegExp(item.key).test(req.url)) { pathType = item.type pathTestRes = new RegExp(item.key).exec(req.url)[0] break; } } for (const type in cdn) { if (type === pathType) { logger.group.ready(`Match CDN ${pathType}: ` + req.url); for (const key in cdn[type]) { const url = cdn[type][key] + req.url.replace(pathTestRes, '') console.log(url); urls.push(url) } logger.group.end() } } } let res; if (urls.length) res = FetchEngine(urls) else res = fetch(req) if (res && NPMMirror && new RegExp(location.origin).test(req.url)) { const ext = fullPath(fullPath(req.url)).split('.').pop() const contentType = getContentType(ext) res = res .then(res => res.arrayBuffer()) .then(buffer => new Response(buffer, { headers: { \"Content-Type\": contentType } })) .catch(() => null) } return res } const fullPath = (url) => { url = url.split('?')[0].split('#')[0] if (url.endsWith('/')) { url += 'index.html' } else { const list = url.split('/') const last = list[list.length - 1] if (last.indexOf('.') === -1) { url += '.html' } } return url } async function progress(res) { return new Response(await res.arrayBuffer(), { status: res.status, headers: res.headers }) } function createPromiseAny() { Promise.any = function (promises) { return new Promise((resolve, reject) => { promises = Array.isArray(promises) ? promises : [] let len = promises.length let errs = [] if (len === 0) return reject(new AggregateError('All promises were rejected')) promises.forEach((p) => { if (p instanceof Promise) { p.then( (res) => resolve(res), (err) => { len-- errs.push(err) if (len === 0) reject(new AggregateError(errs)) } ) } else { reject(p) } }) }) } } function fetchAny(reqs) { const controller = new AbortController() return reqs.map(req => { return new Promise((resolve, reject) => { fetch(req, { signal: controller.signal }) .then(progress) .then(res => { controller.abort() if (res.status !== 200) reject(null) else resolve(res) }) .catch(() => reject(null)) }) }) } function fetchParallel(reqs) { const abortEvent = new Event(\"abortOtherInstance\") const eventTarget = new EventTarget(); return reqs.map(async req => { const controller = new AbortController(); let tagged = false; eventTarget.addEventListener(abortEvent.type, () => { if (!tagged) controller.abort(); }) return new Promise((resolve, reject) => { fetch(req, { signal: controller.signal, }).then(res => { tagged = true; eventTarget.dispatchEvent(abortEvent) if (res.status !== 200) reject(null) else resolve(res) }).catch(() => reject(null)) }) }); } const FetchEngine = (reqs) => { if (!Promise.any) createPromiseAny(); return Promise.any(fetchParallel(reqs)).then(res => res) .catch((e) => { if (e == \"AggregateError: All promises were rejected\") { return Promise.any(fetchAny(reqs)) .then((res) => res) .catch(() => null); } return null; }); }; const getContentType = (ext) => { switch (ext) { case 'js': return 'text/javascript' case 'html': return 'text/html' case 'css': return 'text/css' case 'json': return 'application/json' case 'webp': return 'image/webp' case 'jpg': return 'image/jpg' case 'jpeg': return 'image/jpeg' case 'png': return 'image/png' case 'gif': return 'image/gif' case 'xml': return 'text/xml' case 'xsl': return 'text/xml' case 'webmanifest': return 'text/webmanifest' case 'map': return 'application/json' case 'bcmap': return 'image/vnd.wap.wbmp' case 'wbmp': return 'image/vnd.wap.wbmp' case 'bmp': return 'image/bmp' case 'ico': return 'image/vnd.microsoft.icon' case 'tiff': return 'image/tiff' case 'tif': return 'image/tiff' case 'svg': return 'image/svg+xml' case 'svgz': return 'image/svg+xml' case 'woff': return 'application/font-woff' case 'woff2': return 'application/font-woff2' case 'ttf': return 'application/font-ttf' case 'otf': return 'application/font-otf' case 'eot': return 'application/vnd.ms-fontobject' case 'zip': return 'application/zip' case 'tar': return 'application/x-tar' case 'gz': return 'application/gzip' case 'bz2': return 'application/x-bzip2' case 'rar': return 'application/x-rar-compressed' case '7z': return 'application/x-7z-compressed' case 'doc': return 'application/msword' case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' case 'xls': return 'application/vnd.ms-excel' case 'xlsx': return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' case 'ppt': return 'application/vnd.ms-powerpoint' case 'pptx': return 'application/vnd.openxmlformats-officedocument.presentationml.presentation' case 'pdf': return 'application/pdf' case 'txt': return 'text/plain' case 'rtf': return 'application/rtf' case 'mp3': return 'audio/mpeg' case 'wav': return 'audio/x-wav' case 'ogg': return 'audio/ogg' case 'mp4': return 'video/mp4' case 'm4v': return 'video/x-m4v' case 'mov': return 'video/quicktime' case 'avi': return 'video/x-msvideo' case 'wmv': return 'video/x-ms-wmv' case 'flv': return 'video/x-flv' case 'swf': return 'application/x-shockwave-flash' case 'mpg': return 'video/mpeg' case 'mpeg': return 'video/mpeg' case 'mpe': return 'video/mpeg' case 'mpv': return 'video/mpeg' case 'm2v': return 'video/mpeg' case 'm4a': return 'audio/mp4' case 'aac': return 'audio/aac' case 'm3u': return 'audio/x-mpegurl' case 'm3u8': return 'application/vnd.apple.mpegurl' case 'pls': return 'audio/x-scpls' case 'cue': return 'application/x-cue' case 'wma': return 'audio/x-ms-wma' case 'flac': return 'audio/flac' case 'aif': return 'audio/x-aiff' case 'aiff': return 'audio/x-aiff' case 'aifc': return 'audio/x-aiff' case 'au': return 'audio/basic' case 'snd': return 'audio/basic' case 'mid': return 'audio/midi' case 'midi': return 'audio/midi' case 'kar': return 'audio/midi' default: return 'text/plain' } }"},{"title":"","date":"2023-12-31T13:30:05.740Z","updated":"2023-12-31T13:30:05.740Z","comments":true,"path":"about/index.html","permalink":"https://nanaeo.cn/about/index.html","excerpt":"","text":"Hi, I’m Mlikiowa!是一位正在创作与做出改变的大学生,正在思考着知识与生活,并且为此刻而庆幸着… ExpPrevious 与Ghost在System游玩,Win酱还是Win7的样子。 2015 在Win10萌芽的时代,遇见CoolQ后咱变成了一位开发者. 2016 时间过去一年,我知道我不会一直待在这个圈子里面,于是很快我直接脱离了Plugins的开发,开始开发桌面软件,并尝试着运营,结果是必然失败的,年纪 经济 技术都在限制着发挥。 2017 在这个年份,基于TencentQQ 和 Http1.1的协议研究,对我影响巨大,借此契机我学习了大量前端知识(IE tester甚至还可以运行),贴吧火热的年代总是牛人出没,因此我同年参与大型IM设计,负责部分协议的完成。 2018 前端知识基础之上缺少web开发使我迫切的接触了PHP,同时补习了CPP开发经验,并开发桌面动态壁纸项目等较成熟项目 2019 在初中毕业前的学习到此为止,我那一年开始写博客,并且了解WEB渗透知识 2020 高中忙忙碌碌的自己,完成了某网站的项目,Linux开始频繁出现在我的眼前这一年对图形编程有所提高,审美提高,但是核心技术部分未有较大突破。 2021 这年因高中学业为主,是站长的生活而非一个有理想的开发者,severless等新技术出现在眼前告诉着我众多新技术诞生,我开始尝试各种新技术新方案巨大的收获是开始活跃于开源平台. 2022 学习Python与Nodejs"},{"title":"所有分类","date":"2023-12-31T13:30:05.752Z","updated":"2023-12-31T13:30:05.752Z","comments":true,"path":"categories/index.html","permalink":"https://nanaeo.cn/categories/index.html","excerpt":"","text":""},{"title":"我的朋友们","date":"2023-12-31T13:30:05.752Z","updated":"2023-12-31T13:30:05.752Z","comments":true,"path":"friends/index.html","permalink":"https://nanaeo.cn/friends/index.html","excerpt":"My Friends","text":"My Friends 友情链接自助申请https://github.com/MliKiowa/BlogFriend MySite 12345Name:Mlikiowa Home Villagedescription:A little Village With MlikiowaUrl:https://nanaeo.cn/avatar(100x100):https://q1.qlogo.cn/g?b=qq&nk=1627126029&s=100siteshot:"},{"title":"所有标签","date":"2023-12-31T13:30:05.752Z","updated":"2023-12-31T13:30:05.752Z","comments":true,"path":"tags/index.html","permalink":"https://nanaeo.cn/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"我与我所做的事","slug":"2024","date":"2023-12-30T16:00:00.000Z","updated":"2023-12-31T13:30:05.740Z","comments":true,"path":"2023/12/30/2024/","link":"","permalink":"https://nanaeo.cn/2023/12/30/2024/","excerpt":"","text":"近况很久没更新博客了,我觉得回来水一篇,大家也不用考虑我会跑路了,博客域名续了10年,别问钱哪里来的,问就是免费报销的。说回来,很久没写文了不是别的原因,就是因为没米赚没什么回报,而且说仅仅为了写文干什么没有动力,如果为了赚流量为什么不恰烂钱所以说不如鸽了躺在床上,但是最近在写项目,顺便空闲时间给博客直接改造升级一波,然后顺手也写了篇博文总结下最近。 对于整个站点的优化内部:我对原来的sw.js切换成了官方的Service-Worker.js 然后官方的缓存策略还是很给力的,同时换了张4K背景图格式为WEBP,由原来的vercel拉去githubpage镜像资源改为了vercel也同步生成。同时对老掉牙的Volantis版本升级到了5.8.x版本 外部:对英语字体换成了仿苏芙比字体,可以看到非常Cute,这个字体大家偷的时候注意下,不要用于商用,是仿的游戏人物手写,而且我是在b站up那里偷来的,很遗憾不支持中文哦。 虽然修改很少,但是Volantis爆改这样的配色这样的字体,你绝对没见过第二家。 开源项目 NuCat刚刚不是说最近在做项目吗,诺?下面就是 最近把我老腰要了的项目 一切的源头正在上网的我收到了WinRar让我付费还是看广告的两难选项,我肯定是一个都不会选的,那么眼下我只能找其它免费的压缩软件了,由7zip bandzip很多优秀的产品,但是有没有想过bandzip也是付费的,7zip的界面过于复古,那么对于我这种既要又要的人,能不能有一个 开源 免费 可以换皮肤 支持多语言 又不那么臃肿的压缩软件呢,也许但是仍未被我发现,但是有没有可能我可以写,在这种原因驱动下我开始了NuCat压缩软件的开发。 工具与环境这个很好选,按照习惯我直接选择 CMAKE+MSVC+VSCODE ,虽然是单平台开发,但是CMAKE可以很方便设置依赖 设置参数 同时可读性高,MSVC则是比较优秀的CPP编译器,VSCODE和VS开发CPP都还行,但是VS有时候容易抽风。 食材的选材数据交换和数据储存肯定是Json格式,而对于界面和我的需求相呼应的选项肯定不是QT ,WIN UI 2/3 等等,这类不符合我像一天一老婆的习惯,而且本身我UI不是特别擅长,如果我有位朋友会写WEB,灵感不就来了吗,基于各种原因Webview来展示界面就是最佳选项,cpp上在win32可用webview有很多,但cef electron等等库都与我的小而美冲突,要小小的才可爱,于是我们可以敲定webview2作为核心技术,但是在开发中对com等等不太熟悉吧,根据onebot我们得出一切皆可one,那么肯定来说webview2作为可选引擎来进行封装的库是有的,可以切换浏览器内核,接口操作上比webview2提供的api好用,果然在我们的寻找中找到webview/webview这个项目,我将这个项目作为我们的webview,然后我们还剩一个问题就是说解压压缩怎么办,涉及算法而且各种格式兼容过于麻烦摆在我的选择只有两条,调用7zip的命令行或者sdk,但是调7zip命令行需要按照7zip,使用sdk又如webview2一样接口难以操作,我找到bit7z库提供了对7zip的动态库操作,这样我们就找到了我们所有需要的库。 编码的选择一切都很规范 bit7z yyjson webview/webview都是支持utf8,但是存在一个问题我是针对WinX64进行开发,采用UTF16或者ANSI调用才能正常调用接口,所以我们大部分采用UTF8,少部分WIN API进行UTF8转UTF16操作,按照规范执行内码:UTF8外码:UTF16 开发体验1.很久没有再次开发过WIN32 窗口程序了,上次是N年前了,我已经很久没开发过了,本次可以说我是傻瓜,因为WEBVIEW的com技术我没弄过,弄懂这个到放弃我直接换库了,还有就是无边框窗口保留阴影和窗口随意移动花费了很多时间,无边框会在上方有6px白边问题 主要是因为我想保留窗口阴影同时让他无边框,但是这样会存在6px非客户区 ,解决方法就是放弃阴影,然后用dwm api再绘出来,当然还有其它方案,比如自己用gdi绘阴影,但是确实只能说麻烦。2.找罪受就来写这个,查资料没给我送走,webview/webview虽然说好于webview2体验,但是说它屏蔽大量操作,resize webview都做不到,没办法,我只能爆改他的代码了,体验非常的差 总结一下没事不要瞎折腾,对于写这Nucat压缩软件这是就像赛博顶真一样,绕了路,WIN11 预览版内置压缩软件 WIN10正式版都是能解压ZIP RAR等常见的格式,所以说为什么这么麻烦,大家静静等待就行,或者说不嫌弃7Zip丑,还是可以用用7zip的。 至/2024收回上面的话,至此讲点别的吧,马上将要到来2024,回想起来觉得什么也没有干,从前的雄心破碎在着畸形的互联网,不知道什么在推动着我对这份行业和对这专业的热爱,也许是从前一句论坛上的坚持下去亦或者是n年前贴友的相互激励,在这个流量与互联网畸形的时代,我仍然坚持着少刷短视频 多创造一些属于自己的东西,抛开阴霾,让我们忘记掉2023一切的劳累与不如意 ,带着期望来到2024,我们的路依然漫漫","categories":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/categories/DevLog/"}],"tags":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/tags/DevLog/"},{"name":"Gauss","slug":"Gauss","permalink":"https://nanaeo.cn/tags/Gauss/"}]},{"title":"高斯滤波","slug":"GaussWave","date":"2022-08-13T16:00:00.000Z","updated":"2023-12-31T13:30:05.740Z","comments":true,"path":"2022/08/13/GaussWave/","link":"","permalink":"https://nanaeo.cn/2022/08/13/GaussWave/","excerpt":"高斯滤波的实现","text":"高斯滤波的实现 本文提示本文提供了相关代码和算法仅为示例学习,并非标准案例,并且OpenCV提供了高斯滤波函数,如果遇到不明白的概念和地方可以参考引用文章理解,也可以尝试在搜索引擎上搜索相关概念和图片示例,由于本站资源原因,暂不提供图片。 tips: 本文为了方便仅是灰度图片处理如果需要彩色图片应该尝试修改代码三种通道进行分别处理或其它方法。 概念理解(部分来自百科等)滤波滤波就对图像像素点及其邻域点的灰度值按照一定的参数规则进行加权平均,可以有效滤去理想图像中叠加的高频噪声。常用的滤波有线性滤波、中值滤波、均值滤波、双边滤波、高斯滤波等。滤波有抑制噪声的作用,但这会使得图像边缘模糊。(摘自别的地方) 低通滤波低通滤波是一种过滤方式,规则为低频信号能正常通过,而超过设定临界值的高频信号则被阻隔、减弱,图像处理领域可用来模糊。 高通滤波高通滤波(high-pass filter) 是一种过滤方式,规则为高频信号能正常通过,而低于设定临界值的低频信号则被阻隔、减弱。但是阻隔、减弱的幅度则会依据不同的频率以及不同的滤波程序(目的)而改变,图像处理领域可用于锐化。 高斯滤波高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程,对处理呈现正态分布(高斯分布)的噪声(包括图像噪声)效果显著。tips: 常用高斯模糊就是使用高斯滤波完成的, 高斯模糊是低通滤波的一种, 也就是滤波函数是低通高斯函数, 但是高斯滤波是指用高斯函数作为滤波函数, 至于是不是模糊,要看是高斯低通还是高斯高通, 低通就是模糊, 高通就是锐化。 核算子、模板、结构都是一种当我们进行图像处理时时,使用到的权用一个矩阵表示,可以利用该矩阵计算对应像素,同时我们叫这个矩阵为核算子、模板、结构。(示例见前提指明)大小可小可大,并且一般为奇数,Que:核大小为什么是都是类似3×3/5×5 奇数呢?其中一个原因是定位中心锚点,偶数是无法确定中心点的。 滤波核当进行滤波时,里面是核的内容是权重并且可以用于处理像素,那么该核称为滤波核。(通俗解释 专业解释 请查询资料) 归一化就是生成核或者说模板加起来的权不为一,这时候我们核内每一个值除以核内总值,就实现了归一化。 卷积核如果一个核被用于卷积那么该核也可以被称为卷积核。(通俗解释 专业解释 请查询资料) 高斯核那么高斯核固然就是高斯分布生成的核了 环境与依赖Python 本次使用的编程语言OpenCV 跨平台计算机视觉库Windows11 本文中代码运行系统 OpenCv库安装(清华源 可自行切换) 12pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-pythonpip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python 举例最终滤波核示例 (提示:权请保证和为1 此处已经归一化 但并非真实情况)0.1 0.1 0.20.1 0.1 0.10.1 0.1 0.1 为3×3网格坐标结构该模板大小 3×3 算法过程高斯滤波实现方法看完以上相信各位并没有很多理解,并不要紧,联系实际我们进一步进行高斯滤波通常情况下有两种实现方式,一是用离散化窗口滑窗卷积, 另一种通过傅里叶变换,其中第一种毕竟常见,可能这时候有人又问了,这又是什么,别急,咱先慢慢来,离散化窗口滑窗卷积其实就是进行有限次的移动核运算区域的卷积运算,那么我们可以开始了。 算法过程0.图像灰度处理 (为了方便) 生成滤波核 进行卷积处理图像 生成滤波核(此处为一维高斯函数) sigma 为标准差 图像平滑程度取决于该值我们使用高斯函数进行生成对应滤波核离中心点越远那么边缘值的权值越小,我们依照高斯二维函数就可以生成对应滤波核。代码具体参考如下 123456789def GaussKernel(size,k,sigma): _t = np.zeros((size,size),np.float32) for i in range (size): for j in range (size): norm = math.pow(i-k,2) + pow(j-k,2) _t[i,j] = math.exp(-norm/(2*math.pow(sigma,2)))/2*math.pi*pow(sigma,2) sum = np.sum(_t) kernel = _t/sum return kernel 卷积生成然后我们使用对应的滤波权值进行乘以像素值,就可以生成新值,但是滤波核仅3×3大小,我们在原图像每一个像素点运算一次,即可生成新的图形。运算为: 每个像素点周围点 权×值 的和为中心点新值。 1234567891011def mygaussFilter(img_gray,kernel): h,w = img_gray.shape k_h,k_w = kernel.shape for i in range(int(k_h/2),h-int(k_h/2)): for j in range(int(k_h/2),w-int(k_h/2)): sum = 0 for k in range(0,k_h): for l in range(0,k_h): sum += img_gray[i-int(k_h/2)+k,j-int(k_h/2)+l]*kernel[k,l] img_gray[i,j] = sum return img_gray 样例代码1234567891011121314151617181920212223242526272829303132333435363738394041import mathimport cv2import numpy as npdef GaussKernel(size,k,sigma): _t = np.zeros((size,size),np.float32) for i in range (size): for j in range (size): norm = math.pow(i-k,2) + pow(j-k,2) _t[i,j] = math.exp(-norm/(2*math.pow(sigma,2)))/2*math.pi*pow(sigma,2) sum = np.sum(_t) kernel = _t/sum return kerneldef mygaussFilter(img_gray,kernel): h,w = img_gray.shape k_h,k_w = kernel.shape for i in range(int(k_h/2),h-int(k_h/2)): for j in range(int(k_h/2),w-int(k_h/2)): sum = 0 for k in range(0,k_h): for l in range(0,k_h): sum += img_gray[i-int(k_h/2)+k,j-int(k_h/2)+l]*kernel[k,l] img_gray[i,j] = sum return img_grayif __name__ == '__main__': img = cv2.imread("demo.jpg") img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) img_g = img_gray.copy() k=1 size = 2*k+1 kernel = gausskernel(size,k,1.5) print(kernel) img_B,img_G,img_R = cv2.split(img) img_gauss_B = mygaussFilter(img_B,kernel) img_gauss_G = mygaussFilter(img_G,kernel) img_gauss_R = mygaussFilter(img_R,kernel) img_gauss = cv2.merge([img_gauss_B,img_gauss_G,img_gauss_R]) img_comp = np.hstack((img,img_gauss)) cv2.imshow("gauss",img_comp) cv2.waitKey(0) 直接OpenCV操作(非原理实现方案 使用封装方法)1234567import cv2Gn=cv2.imread("Gaussian_noise.jpg") Gf=cv2.GaussianBlur(Gn,(3,3),0,0)cv2.imshow("噪声图像",Gn)cv2.imshow("滤波图像",Gf)cv2.waitKey()cv2.destroyAllWindows() Que: 边界点的处理如果一个点处于边界,周边没有足够的点,怎么办?一个变通方法,就是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。当然我们这里很简单,就是进行矩阵补零上去,用零进行模拟完整矩阵。 总结高斯滤波可以让图像高斯噪声降低,并且平滑图像,并且opencv等库已经提供封装,我们可以很快的使用 文章引用高斯滤波https://blog.csdn.net/weixin_51571728/article/details/121527964高斯滤波核https://blog.csdn.net/qqq777_/article/details/112800310有关线性滤波、滤波核的基本概念(概念理解)https://blog.csdn.net/weixin_42664622/article/details/103672899数字图像处理基础 — 高斯滤波https://zhuanlan.zhihu.com/p/82569305图像滤波原理(不推荐)https://view.inews.qq.com/a/20220425A06HHF00 提示该文章并不准确,如果有错误请积极指出。","categories":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/categories/DevLog/"}],"tags":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/tags/DevLog/"},{"name":"Gauss","slug":"Gauss","permalink":"https://nanaeo.cn/tags/Gauss/"}]},{"title":"新博客建好啦","slug":"NewBlog","date":"2022-08-04T16:00:00.000Z","updated":"2023-12-31T13:30:05.740Z","comments":true,"path":"2022/08/04/NewBlog/","link":"","permalink":"https://nanaeo.cn/2022/08/04/NewBlog/","excerpt":"Hi Hexo,I am Mlikiowa!是全新的Hexo/vlolantis博客,我又回来写博客了!","text":"Hi Hexo,I am Mlikiowa!是全新的Hexo/vlolantis博客,我又回来写博客了! 回忆2019.Previous 使用过Emlog Wordpress来搭建博客,使用过各种博客系统,体验不能说差,只能说没有。 2019.Done 开始尝试在CSDN 简书平台发布自己的文章,但是后来因为咱不太喜欢平台限制,遂转入Typecho来搭建博客。 2020.Done 一开始typecho小而美的感觉是很不错的体验,加上我正好会使用PHP,能自己搓插件,所以体验还不错。 2021.Done 期间域名备案和准备高考,并搭建了一个运行在国内的typecho博客。 2022.Done 上半年:因为没有空闲时间打理博客,备案因无法联系注销,后来意外将电脑中typecho的备份删除,故跑路。下半年:借大佬之手找回了数据,但准备重新开始,于是依靠Hexo搭建了全新的博客,走上了白嫖之路。 事件前言: 各位好啊,以上就是我的悲剧经历了,现在我又新搭了博客,使用Hexo博客来进行搭建,依托serverless和action等工具实现。 备案悲剧: 之前我一直使用typecho,服务器和域名在国内备案,高中学业繁忙,每天都忙着学习。所以个人就没有时间处理相关的事情,审核电话我也没有接到,导致国内备案掉了,加上本来博文写的就不怎么样,后来干脆就直接删掉跑路了,虽然后面通过大佬进行找回了,我也是决定从头开始了。 计划上线: 直到2022年的下半年毕业,我终于想起时修理博客,却又嫌折腾博客麻烦,国内备案审核挺烦。本来是计划在另一位大佬那里使用Typecho搭建博客,因为typecho某些地方有些实在是难受,导致我实在是忍受不了痛苦了(恼,于是很快决定更换博客系统。 实际行动: 于是我决定博客使用hexo搭建,并且以低成本实现搭个稳定的博客,本博客是非常容易在新设备上使用,轻松可以在新的地方迁移使用,将跑路可能性降到最低了。 博客运行环境 Name Content Blog Hexo Theme volantis platform vercel&Github domain nanaeo.cn 小吐槽: 之前还想试试hexo-theme-diaspora这样的主题,这款博客是从wp移植到hexo的,介绍图很好看,可惜作者没更新了,于是我只能选择其它主题了。所以我换成了volantis主题 (npm -i hexo-theme-volantis 可以轻松安装),个人感觉色调和布局都很好看,可玩程度很高。 博客搭建本博客源码项目https://github.com/MliKiowa/MliKiowa.github.io 本博客通过使用GithubAction等方式生成部署分发博文到如githubpage vercel等服务商至于推送到cos/oss .etc storage bucket还是算了,毕竟谁用谁欠费(容易挨打,好点情况也得宕了)。 小提示: 使用多服务商涉及到Dns分流,像腾讯Dnspod的这种解析服务要交钱升级才能使用,非常的难受,所以我考虑使用动态Api进行切换dns解析。 小吐槽: 居然github workflow只有已经写好的deploy hugo site to githubpage workflow,没有hexo自动部署的脚步,于是我照猫画虎写了一个Hexo自动部署脚本,但因水平太菜,用这个workflow还得我改了半天。正当我吐槽这么大个github没人发布自动部署脚本的时候,我在github search找到了类似的workflow,但是我已经写完了,难受。 迁移使用 本博客通过以下脚本可以快速迁移,从云端Github下载源码然后在本地进行编写博文,提交后直接在使用action刷新博客。 (该内容已经失效) Tips: 如果你有需要也可以执行以下脚本建立新博客,可以轻松在新设备上运行。 bash.sh 1234git clone https://github.com/MliKiowa/nanaeocd MliKiowa.github.ionpm installhexo g 博客内容 Classification Content Dev Exp Free Developer Site Log Site Maintenance Log Life Log Record your life 小提示: 内容的主要以编程和生活为主,不会有资源推荐,也不接受类似站点友链。 期盼 域名问题: 原来的域名看起来好憨,还被我朋友嘲笑了,因此旧域名怎么能配得上新博客,所以我还是注册个符合气质的新域名啊,所以nanaeo.cn诞生了,寓意没有很特别,全凭感觉来,可爱就对了不是嘛(歪头 跑路问题: 折腾数次各种博客的我真的是太累了,所以本博客能run起来我觉得不是不会去折腾什么新博客了,但是请允许我说一句,我正在努力成为年更博主吧,半年一更就是高产! 内容布局: 咱正在正在摸索,你现在看到的排版全是我正在尝试的,我很少使用Hexo,可以说是全新的萌新,但是让我来慢慢完善应该没有任何问题。 图床问题: 这个问题我根本不知道怎么解决我还是摆烂吧,博文能不放图我绝对不会放图出来。 总结一下: 这就是Mlikiowa全新的博客了,Always believe that something wonderful is about to happen.Let’s go!","categories":[{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/categories/SiteLog/"}],"tags":[{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/tags/SiteLog/"},{"name":"HexoThemes","slug":"HexoThemes","permalink":"https://nanaeo.cn/tags/HexoThemes/"},{"name":"Hexo","slug":"Hexo","permalink":"https://nanaeo.cn/tags/Hexo/"}]}],"categories":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/categories/DevLog/"},{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/categories/SiteLog/"}],"tags":[{"name":"DevLog","slug":"DevLog","permalink":"https://nanaeo.cn/tags/DevLog/"},{"name":"Gauss","slug":"Gauss","permalink":"https://nanaeo.cn/tags/Gauss/"},{"name":"SiteLog","slug":"SiteLog","permalink":"https://nanaeo.cn/tags/SiteLog/"},{"name":"HexoThemes","slug":"HexoThemes","permalink":"https://nanaeo.cn/tags/HexoThemes/"},{"name":"Hexo","slug":"Hexo","permalink":"https://nanaeo.cn/tags/Hexo/"}]}
|
package/feed.json
CHANGED
@@ -4,6 +4,17 @@
|
|
4
4
|
"description": "It is a little blog~",
|
5
5
|
"home_page_url": "https://nanaeo.cn",
|
6
6
|
"items": [
|
7
|
+
{
|
8
|
+
"id": "https://nanaeo.cn/2023/12/30/2024/",
|
9
|
+
"url": "https://nanaeo.cn/2023/12/30/2024/",
|
10
|
+
"title": "我与我所做的事",
|
11
|
+
"date_published": "2023-12-30T16:00:00.000Z",
|
12
|
+
"content_html": "<div class=\"story post-story\"><h2 id=\"近况\"><a href=\"#近况\" class=\"headerlink\" title=\"近况\"></a>近况</h2><p>很久没更新博客了,我觉得回来水一篇,大家也不用考虑我会跑路了,博客域名续了10年,别问钱哪里来的,问就是免费报销的。<br>说回来,很久没写文了不是别的原因,就是因为没米赚没什么回报,而且说仅仅为了写文干什么没有动力,如果为了赚流量为什么不恰烂钱<br>所以说不如鸽了躺在床上,但是最近在写项目,顺便空闲时间给博客直接改造升级一波,然后顺手也写了篇博文总结下最近。</p>\n</div><div class=\"story post-story\"><h2 id=\"对于整个站点的优化\"><a href=\"#对于整个站点的优化\" class=\"headerlink\" title=\"对于整个站点的优化\"></a>对于整个站点的优化</h2><p>内部:<br>我对原来的sw.js切换成了官方的Service-Worker.js 然后官方的缓存策略还是很给力的,同时换了张4K背景图格式为WEBP,由原来的vercel拉去githubpage镜像资源改为了vercel也同步生成。<br>同时对老掉牙的Volantis版本升级到了5.8.x版本</p>\n<p>外部:对英语字体换成了仿苏芙比字体,可以看到非常Cute,这个字体大家偷的时候注意下,不要用于商用,是仿的游戏人物手写,而且我是在b站up那里偷来的,很遗憾不支持中文哦。</p>\n<p>虽然修改很少,但是Volantis爆改这样的配色这样的字体,你绝对没见过第二家。</p>\n</div><div class=\"story post-story\"><h2 id=\"开源项目-NuCat\"><a href=\"#开源项目-NuCat\" class=\"headerlink\" title=\"开源项目 NuCat\"></a>开源项目 NuCat</h2><p>刚刚不是说最近在做项目吗,诺?下面就是 最近把我老腰要了的项目</p>\n</div><div class=\"story post-story\"><h2 id=\"一切的源头\"><a href=\"#一切的源头\" class=\"headerlink\" title=\"一切的源头\"></a>一切的源头</h2><p>正在上网的我收到了WinRar让我付费还是看广告的两难选项,我肯定是一个都不会选的,那么眼下我只能找其它免费的压缩软件了,由7zip bandzip很多优秀的产品,但是有没有想过bandzip也是付费的,7zip的界面过于复古,那么对于我这种既要又要的人,能不能有一个 开源 免费 可以换皮肤 支持多语言 又不那么臃肿的压缩软件呢,也许但是仍未被我发现,但是有没有可能我可以写,在这种原因驱动下我开始了NuCat压缩软件的开发。</p>\n</div><div class=\"story post-story\"><h2 id=\"工具与环境\"><a href=\"#工具与环境\" class=\"headerlink\" title=\"工具与环境\"></a>工具与环境</h2><p>这个很好选,按照习惯我直接选择 CMAKE+MSVC+VSCODE ,虽然是单平台开发,但是CMAKE可以很方便设置依赖 设置参数 同时可读性高,MSVC则是比较优秀的CPP编译器,VSCODE和VS开发CPP都还行,但是VS有时候容易抽风。</p>\n</div><div class=\"story post-story\"><h2 id=\"食材的选材\"><a href=\"#食材的选材\" class=\"headerlink\" title=\"食材的选材\"></a>食材的选材</h2><p>数据交换和数据储存肯定是Json格式,而对于界面和我的需求相呼应的选项肯定不是QT ,WIN UI 2/3 等等,这类不符合我像一天一老婆的习惯,而且本身我UI不是特别擅长,如果我有位朋友会写WEB,灵感不就来了吗,基于各种原因Webview来展示界面就是最佳选项,cpp上在win32可用webview有很多,但cef electron等等库都与我的小而美冲突,要小小的才可爱,于是我们可以敲定webview2作为核心技术,但是在开发中对com等等不太熟悉吧,根据onebot我们得出一切皆可one,那么肯定来说webview2作为可选引擎来进行封装的库是有的,可以切换浏览器内核,接口操作上比webview2提供的api好用,果然在我们的寻找中找到webview/webview这个项目,我将这个项目作为我们的webview,然后我们还剩一个问题就是说解压压缩怎么办,涉及算法而且各种格式兼容过于麻烦摆在我的选择只有两条,调用7zip的命令行或者sdk,但是调7zip命令行需要按照7zip,使用sdk又如webview2一样接口难以操作,我找到bit7z库提供了对7zip的动态库操作,这样我们就找到了我们所有需要的库。</p>\n</div><div class=\"story post-story\"><h2 id=\"编码的选择\"><a href=\"#编码的选择\" class=\"headerlink\" title=\"编码的选择\"></a>编码的选择</h2><p>一切都很规范 bit7z yyjson webview/webview都是支持utf8,但是存在一个问题我是针对WinX64进行开发,采用UTF16或者ANSI调用才能正常调用接口,所以我们大部分采用UTF8,少部分WIN API进行UTF8转UTF16操作,按照规范执行<br>内码:UTF8<br>外码:UTF16</p>\n</div><div class=\"story post-story\"><h2 id=\"开发体验\"><a href=\"#开发体验\" class=\"headerlink\" title=\"开发体验\"></a>开发体验</h2><p>1.很久没有再次开发过WIN32 窗口程序了,上次是N年前了,我已经很久没开发过了,本次可以说我是傻瓜,因为WEBVIEW的com技术我没弄过,弄懂这个到放弃我直接换库了,还有就是无边框窗口保留阴影和窗口随意移动花费了很多时间,无边框会在上方有6px白边问题 主要是因为我想保留窗口阴影同时让他无边框,但是这样会存在6px非客户区 ,解决方法就是放弃阴影,然后用dwm api再绘出来,当然还有其它方案,比如自己用gdi绘阴影,但是确实只能说麻烦。<br>2.找罪受就来写这个,查资料没给我送走,webview/webview虽然说好于webview2体验,但是说它屏蔽大量操作,resize webview都做不到,没办法,我只能爆改他的代码了,体验非常的差</p>\n</div><div class=\"story post-story\"><h2 id=\"总结一下\"><a href=\"#总结一下\" class=\"headerlink\" title=\"总结一下\"></a>总结一下</h2><p>没事不要瞎折腾,对于写这Nucat压缩软件这是就像赛博顶真一样,绕了路,WIN11 预览版内置压缩软件 WIN10正式版都是能解压ZIP RAR等常见的格式,所以说为什么这么麻烦,大家静静等待就行,或者说不嫌弃7Zip丑,还是可以用用7zip的。</p>\n</div><div class=\"story post-story\"><h2 id=\"至-x2F-2024\"><a href=\"#至-x2F-2024\" class=\"headerlink\" title=\"至/2024\"></a>至/2024</h2><p>收回上面的话,至此讲点别的吧,马上将要到来2024,回想起来觉得什么也没有干,从前的雄心破碎在着畸形的互联网,不知道什么在推动着我对这份行业和对这专业的热爱,也许是从前一句论坛上的坚持下去亦或者是n年前贴友的相互激励,在这个流量与互联网畸形的时代,我仍然坚持着少刷短视频 多创造一些属于自己的东西,抛开阴霾,让我们忘记掉2023一切的劳累与不如意 ,带着期望来到2024,我们的路依然漫漫</p>\n\n</div>",
|
13
|
+
"tags": [
|
14
|
+
"DevLog",
|
15
|
+
"Gauss"
|
16
|
+
]
|
17
|
+
},
|
7
18
|
{
|
8
19
|
"id": "https://nanaeo.cn/2022/08/13/GaussWave/",
|
9
20
|
"url": "https://nanaeo.cn/2022/08/13/GaussWave/",
|