作者归档:ning

小程序使用最新版OpenCV教程

本文一步一步教你如何在小程序中使用最新版的OpenCV

安装基础软件

安装基础工具

pacman -S base-devel cmake git

安装以及配置emsdk

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install 2.0.10
./emsdk activate 2.0.10
source ./emsdk_env.sh

配置以及编译OpenCV

进入 https://opencv.org/releases/ 页面下载opencv最新版源码,并解压缩,并进入解压缩后文件夹

取消不需要的OpenCV模块,减少wasm体积

修改platforms/js/opencv_js.config.py文件根据情况,去掉不用的模块

# white_list = makeWhiteList([core, imgproc, objdetect, video, dnn, features2d, photo, aruco, calib3d])
white_list = makeWhiteList([core, imgproc])

配置OpenCV4输出独立的wasm文件

默认OpenCV4会将wasm以base64存到js文件,输出单独wasm文件便于用于微信小程序

打开modules/js/CMakeLists.txt,去掉 SINGLE_FILE参数

# set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1")

配置OpenCV禁用动态执行函数

微信小程序不支持eval()new Function()等动态执行函数,在modules/js/CMakeLists.txt中,增加DYNAMIC_EXECUTION的编译参数屏蔽这些函数的输出

# set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s DYNAMIC_EXECUTION=0")

查看编译参数

emcmake python ./platforms/js/build_js.py -h

编译OpenCV

emcmake python ./platforms/js/build_js.py build_wasm --build_wasm --build_test

build_wasm\bin目录生成了opencv.js,opencv_js.wasm,tests.html文件

压缩wasm

brotli -o build_wasm/bin/opencv_js.wasm.br build_wasm/bin/opencv_js.wasm

运行以及查看Web测试

npm i -g http-server
http-server build_wasm/bin/

在浏览器打开 http://127.0.0.1:8080/tests.html 可以查看测试结果

修改opencv.js适配微信小程序

修改前先将opencv.js格式化一下,微信小程序不支持通过url获取wasm,修改下instantiateAsync方法的else分支里面的代码,让读小程序项目下的opencv_js.wasm文件


        function instantiateAsync() {
          if (
            !wasmBinary &&
            typeof WebAssembly.instantiateStreaming === "function" &&
            !isDataURI(wasmBinaryFile) &&
            !isFileURI(wasmBinaryFile) &&
            typeof fetch === "function"
          ) {
            return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(
              function (response) {
                var result = WebAssembly.instantiateStreaming(response, info);
                return result.then(
                  receiveInstantiatedSource,
                  function (reason) {
                    err("wasm streaming compile failed: " + reason);
                    err("falling back to ArrayBuffer instantiation");
                    return instantiateArrayBuffer(receiveInstantiatedSource);
                  }
                );
              }
            );
          } else {
            // return instantiateArrayBuffer(receiveInstantiatedSource);
            var result = WebAssembly.instantiate("/opencv/opencv_js.wasm.br", info);
            return result.then(
              receiveInstantiatedSource,
              function (reason) {
                err("wasm streaming compile failed: " + reason);
                err("falling back to ArrayBuffer instantiation");
                return instantiateArrayBuffer(receiveInstantiatedSource);
              }
            );
          }
        }

修改OpenCV.js的imread,imshow,VideoCapture方法支持小程序

这些方法定义在modules\js\src\helpers.js文件中,修改后重新编译和生成wasm文件即可

在小程序使用OpenCV.js

const app = getApp()
WebAssembly = WXWebAssembly;
let cv = require('../../opencv/opencv.js');

Page({
  onLoad: function (options) {
    if (cv instanceof Promise) {
      cv.then((target) => {
        console.log(target);
      })
    } else {
      console.log(cv);
    }
  }
})

参考

C# .net framework不使用命令行或第三方库实现服务安装、卸载、停用,启用

网上资料通常都通过命令行调用sc.exe进行,这里介绍一种通过微软提供API实现的方法。代码更加简单,可控性更好。

使用方法

static void Main(string[] args)
{
    if (args.Length == 0) {
        // Run your service normally.
        ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
        ServiceBase.Run(ServicesToRun);
    } else if (args.Length == 1) {
        switch (args[0]) {
            case "-install":
                InstallService();
                StartService();
                break;
            case "-uninstall":
                StopService();
                UninstallService();
                break;
            default:
                throw new NotImplementedException();
        }
    }
}

ServiceControl 类

 public class ServiceControl
    {
        const string ServiceName = "MyService";

        public static bool IsInstalled()
        {
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    ServiceControllerStatus status = controller.Status;
                }
                catch
                {
                    return false;
                }
                return true;
            }
        }

        public static bool IsRunning()
        {
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                if (!IsInstalled()) return false;
                return (controller.Status == ServiceControllerStatus.Running);
            }
        }

        public static AssemblyInstaller GetInstaller()
        {
            AssemblyInstaller installer = new AssemblyInstaller(
                typeof(MyService).Assembly, null);
            installer.UseNewContext = true;
            return installer;
        }

        public static void InstallService()
        {
            if (IsInstalled()) return;

            try
            {
                using (AssemblyInstaller installer = GetInstaller())
                {
                    IDictionary state = new Hashtable();
                    try
                    {
                        installer.Install(state);
                        installer.Commit(state);
                    }
                    catch
                    {
                        try
                        {
                            installer.Rollback(state);
                        }
                        catch { }
                        throw;
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        public static void UninstallService()
        {
            if (!IsInstalled()) return;
            try
            {
                using (AssemblyInstaller installer = GetInstaller())
                {
                    IDictionary state = new Hashtable();
                    try
                    {
                        installer.Uninstall(state);
                    }
                    catch
                    {
                        throw;
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        public static void StartService()
        {
            if (!IsInstalled()) return;

            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    if (controller.Status != ServiceControllerStatus.Running)
                    {
                        controller.Start();
                        controller.WaitForStatus(ServiceControllerStatus.Running,
                            TimeSpan.FromSeconds(10));
                    }
                }
                catch
                {
                    throw;
                }
            }
        }

        public static void StopService()
        {
            if (!IsInstalled()) return;
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    if (controller.Status != ServiceControllerStatus.Stopped)
                    {
                        controller.Stop();
                        controller.WaitForStatus(ServiceControllerStatus.Stopped,
                             TimeSpan.FromSeconds(10));
                    }
                }
                catch
                {
                    throw;
                }
            }
        }
    }

参考

建立了一个独立项目交流群

建立了一个"独立项目交流群",本群主要交流开源项目的运作模式和盈利模式。

大家可以在名字前面加地区,以及熟悉的技能,如“长沙-全栈-ning”,名字建议用昵称。

目前还没有项目启动,大家可以想一想,可以先分享一些开源或者商业案例,慢慢形成讨论氛围。

注意:

  • 群永久免费
  • 卖课永久严禁加入
  • HR暂时严禁加入
  • 以前叫做开源项目交流群,后来发现大家可能不一定选择开源,所以就改一下吧

微信扫码进群

!(独立项目交流群)

Windows下PHP安装Imagick扩展

查看本机PHP版本

php -v

输出

PHP 7.4.14 (cli) (built: Jan  5 2021 15:11:43) ( NTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

可以看到PHP版本为7.4,NTS(非线程安全),64位

下载扩展DLL

  1. 打开 https://pecl.php.net/package/imagick
  2. 找到最新稳定版本,点击后面的DLL
  3. 再打开的页面中,根据上面的PHP版本,选择要下载的DLL

安装

  1. 将下载的压缩文件下的php_imagick.dll放入PHP目录下的ext子目录下
  2. 将压缩文件下的其他DLL文件放到PHP目录
  3. 修改php目录下的php.ini,添加extension=imagick

解决Win10部分程序搜索不到的问题

知乎高分答案是让大家去重装小冰,通常可能是解决不了问题的。

因为情况实际可能是本地应用是以当前用户身份安装的,安装在用户的appdata目录下,然后Windows索引默认排除了用户的appdata目录,所以就搜索不到了。

解决办法:

  • 搜索任意文字,在搜索结果界面,点索右侧三圆点,打开索引选项窗口;

file

  • 在索引选项设置中找到排除目录,将用户的appdata目录从排除目录删除即可。

file

pyenv — 多版本Python(含镜像设置加速下载)

安装pyenv

curl https://pyenv.run | bash

显示已安装python版本

pyenv install --list

设置使用镜像

 export PYTHON_BUILD_MIRROR_URL_SKIP_CHECKSUM=1
 export PYTHON_BUILD_MIRROR_URL="https://npm.taobao.org/mirrors/python/"

安装指定版本Python

pyenv install 3.9.9

运行指定版本Python

pyenv global 3.9.9

查看当前已安装和正在运行的Python版本

pyenv versions

查看已安装版本位置

pyenv prefix 3.9.9

其他

  • pyenv的替代工具是asdf, 可以管理多个语言的版本,包含Python,node,Erlang,Ruby,PHP,Mysql,Postgres等

参考

pipx — 在隔离的环境中安装和运行Python应用程序

pipx 介绍

在隔离的环境中安装和运行Python应用程序,安装的程序都在自己隔离的环境,不用考虑依赖冲突,且可以安装多个版本,可以非root身份运行程序。官网:https://github.com/pypa/pipx

安装 pipx

python3 -m pip install --user pipx

配置自动完成

pipx completions

使用 pipx 安装

pipx install pipenv

通过 url 安装

pipx install git+https://github.com/psf/black.git
pipx install git+https://github.com/psf/black.git@branch  # branch of your choice
pipx install git+https://github.com/psf/black.git@ce14fa8b497bae2b50ec48b3bd7022573a59cdb1  # git hash
pipx install https://github.com/psf/black/archive/18.9b0.zip  # install a release

列出已安装应用

pipx list

升级

pipx upgrade pipenv

运行

pipx run pipenv

指定版本运行

pipx run APP==1.0.0

通过 url 运行

pipx run https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py

卸载

pipx  uninstall pipenv

卸载所有

pipx  uninstall-all

显示帮助

pipx  -h

Windows编译pdfium

确定 Visual Studio 和 Windows SDK 版本

  • 需要Visual Studio2017 及以上
  • Windows SDK 10.0.19041 及以上(需要Debugging Tools For Windows)
  • 安装Desktop development with C++
  • 安装MFC/ATL support

设置全局代理

set DEPOT_TOOLS_WIN_TOOLCHAIN=0
set DEPOT_TOOLS_UPDATE=0
set http_proxy=127.0.0.1:1080
set https_proxy=127.0.0.1:1080
set GYP_MSVS_VERSION=2022

安装 depot_tools

  • 下载 depot_tools ,并解压缩到d:\sdk\depot_tools目录
  • 系统path环境变量添加d:\sdk\depot_tools
  • 将然后设置vs2022_install环境变量为D:\Program Files\Microsoft Visual Studio\2022\Community
  • 运行gclient

验证Python安装

命令行输入where python,确保D:\sdk\depot_tools\python.bat在第一条,
如果不是则修改PATH环境变量顺序

下载 pdfium 代码

以管理员身份打开命令提示符,进入D:\cproject\pdfium目录

gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
gclient sync

生成构建文件

cd pdfium
gn args --ide=vs out\Default

out\Default\args.gn如下

# Set build arguments here. See `gn help buildargs`.

use_goma = false

clang_use_chrome_plugins = false

pdf_is_standalone = true

pdf_use_skia = false
pdf_use_skia_paths = false

is_debug = false

is_component_build = true

pdf_is_complete_lib = false

pdf_enable_xfa = false

pdf_enable_v8 = false

target_cpu = "x86"

is_clang = true

禁用v8可以提高编译性能,使用clang可以提高编译和程序运行性能,如果VS编译不通过,就尝试使用clang试试。

编译测试

编译测试程序

ninja -C out\Default pdfium_test # 编译测试程序
pdfium_test --help # 运行测试程序

编译windows动态库dll

# 首先需要将 is_component_build 改为 true
ninja -C out\Default pdfium # 编译动态库

参考

企业招聘10倍程序员和0.5倍程序员的区别

首先,10倍只能是偶尔某些任务,并不是所有任务类型能10倍效率。

其次,编程是一项需要协作的工作,很多时候是流水线试操作的。且小组的一个10倍程序员可能没法让整个小组效率都能10倍,真正10倍程序员也不太好鉴别,或者不存在(干每项工作都10倍?)。而一个0.5倍程序员,却通常可以让整个小组的效率都变为0.5倍甚至更慢,而这通常非常容易鉴别。当我们在谈论10倍程序员时,通常我们只是想找一个1倍的,是因为大部分都还没有达到1倍;

所以,想招聘10倍程序员,成立10倍团队是不现实的,收益和成功可能性远少于踢掉团队0.x的程序员,木桶定律才是优先需要考虑的,企业不要企图花费太大精力企图去招聘10倍程序员,而是要防止招聘到0.x倍程序员,要时刻警惕0.x倍程序员。

对于个人来说,哪怕你真成为10倍程序员,公司不会给你10倍工资,要想成为10倍效率程序员,可能不太行得通,那么价值上的10倍可行性怎么样呢,可能更值得探讨?

MySQL分段统计函数INTERVAL和ELT

需求

期末考试成绩出来了,结果需要分为不及格(0-59),合格(60-84),优秀(80+)三个段,老师需要统计每个段成绩的分布情况。

分数表score结构如下:

id int
user_id int
score int

使用INTERVAL函数对学生成绩分段

SELECT user_id,score,INTERVAL(score,60,85) as step from score

INTERVAL函数会根据score返回0(少于60),1(60-74),2(85以及以上)

INTERVAL返回的结果进行分组:

SELECT INTERVAL(score,60,85),COUNT(*) AS num as step from score GROUP BY INTERVAL(score,60,85)

得到:

0, 5
1, 80
2, 15

使用ELT函数为阶段命名

ETL方法会建立重命名,将1,2,3分别转化为不及格,合格,优秀,但是etl不能是从0开始的,所以我们可以在INTERVAL分组时加一个0,将0分以下的划分为0,0-59的划为1,依次类推

SELECT INTERVAL(score,0,60,85),COUNT(*) AS num as step from score GROUP BY INTERVAL(score,60,85)

得到:

1, 5
2, 80
3, 15

最终SQL:

SELECT ELT(INTERVAL(score,0,60,85),"不及格","合格","优秀"),COUNT(*) AS num as step from score GROUP BY ELT(INTERVAL(score,0,60,85),"不及格","合格","优秀")

得到:

不及格, 5
合格, 80
优秀, 15