最新版的Anaconda命令与旧版稍有差异,这里记录以备查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
查看Anaconda版本 
conda --version

conda create --name snowflakes biopython
conda activate snowflakes(激活环境)
conda info --envs
conda activate(退回默认环境)

conda create --name snakes python=3.5
conda activate snakes(激活环境)
conda info --envs
python --version
conda activate(退回默认环境)

conda search beautifulsoup4
conda install beautifulsoup4
conda list

查看帮助
conda --help
conda update -h

.condarc设置源

1
2
3
4
5
channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- defaults
show_channel_urls: true
ssl_verify: true

pip/pip.ini

1
2
3
[global]
trusted-host = pypi.tuna.tsinghua.edu.cn
index-url = https://pypi.tuna.tsinghua.edu.cn/simple


旧版本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
conda --version
python --version

conda upgrade --all

移除环境
conda remove -n py35 --all(conda env remove -n python36 # 测试可行)
移除包
conda remove -n py35 iopro
conda create --name py35 python=3.5


activate py35
deactivate(deactivate python36 )

conda install pyqt=5
conda remove pyqt
conda update package_name(升级)
python -m pip install --upgrade pip(貌似是升级pip)

conda list

conda info -e(conda env list)

pip install labelImg(安装)
pip uninstall requests

pip install --upgrade labelImg(升级)

conda env export --file python36_20190106.yml
conda env create -f d:\python36_20190106.yml

webpack是nodejs开发中,经常需要用到工具;貌似不同的版本的配置稍有差异,经常碰到各种错误
这里本人基于目前最新版本进行了配置测试

安装相关package

创建目录
mkdir webpacktest && cd webpacktest

npm init -y
npm i -D webpack webpack-cli

npm i -D html-webpack-plugin html-loader

npm i -D webpack-dev-server

npm i -D @babel/core babel-loader @babel/preset-env

npm i -D file-loader

npm i -D node-sass style-loader css-loader sass-loader mini-css-extract-plugin

package.json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"name": "webpacktest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"start:dev": "webpack-dev-server"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"babel-loader": "^8.0.6",
"css-loader": "^3.1.0",
"file-loader": "^4.1.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.39.0",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2"
}
}

webpack.config.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use:{
loader: 'babel-loader'
}
},
{
test: /\.html$/,
use: [{
loader: 'html-loader',
options: {
minimize: true
}
}],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
test:/\.scss$/,
use:[
"style-loader",
"css-loader",
"sass-loader"
]
}
]
},
plugins: [new HtmlWebPackPlugin({
template: './src/index.html',
filename: './index.html'
}),
new MiniCssExtractPlugin({
filename:"[name].css",
chunkFilename:"[id].css"
})
]
}

输入命令 npm run build进行打包
npm run start:dev进行开发

安装静态服务器
npm i http-server -g
http-server -o(运行服务器)

我们可以将图像的BGR颜色空间转换到HSV颜色空间,然后基于HSV颜色空间对图片颜色处理

HSV表示Hue, Saturation, Value,其中Hue范围0~180,Saturation范围0~255,Value范围0~255

那么我们怎么根据HSV颜色空间提取图像中的颜色呢?这里有一个指导(在具体实践中,我们可以根据HSV的直方图作参考)

这里的例子是提取图像中的苹果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {

Mat img = Imgcodecs.imread("data/apple.jpg");
Mat imgHSV = new Mat(img.rows(), img.cols(), CvType.CV_8UC3);

// RGB->HSV
Imgproc.cvtColor(img, imgHSV, Imgproc.COLOR_BGR2HSV);


Scalar lower_hsv = new Scalar(0,90,70);
Scalar upper_hsv = new Scalar(15,230,255);

Mat mask = new Mat();
Core.inRange(imgHSV, lower_hsv, upper_hsv, mask);
Mat blackImg = new Mat();
Core.bitwise_and(img, img, blackImg,mask);

HighGui.imshow("原图", img);
HighGui.imshow("mask", mask);
HighGui.imshow("颜色过滤", blackImg);
HighGui.waitKey(0);
System.exit(0);
}



图像直方图反映了图像像素的密度分布,下面是BGR图像三通道的直方图测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public static void main(String[] args) {

Mat hello =Imgcodecs.imread("data/lena.jpg");
List<Mat> bgrPlanes = new ArrayList<>();
Core.split(hello, bgrPlanes);

MatOfFloat histRange = new MatOfFloat(0, 256);
int histSize = 256;
//MatOfInt channels = new MatOfInt(0);

boolean accumulate = false;

//Mat histImg1 = new Mat();
Mat bHist = new Mat(), gHist = new Mat(), rHist = new Mat();

Imgproc.calcHist(bgrPlanes, new MatOfInt(0), new Mat(), bHist, new MatOfInt(histSize),histRange,accumulate);
Imgproc.calcHist(bgrPlanes, new MatOfInt(1), new Mat(), gHist, new MatOfInt(histSize), histRange, accumulate);
Imgproc.calcHist(bgrPlanes, new MatOfInt(2), new Mat(), rHist, new MatOfInt(histSize), histRange, accumulate);

int histW = 512, histH = 400;
int binW = (int) Math.round((double) histW / histSize);

Mat histImage = new Mat( histH, histW, CvType.CV_8UC3, new Scalar( 255,255,255) );

Core.normalize(bHist, bHist, 0, histImage.rows()-20, Core.NORM_MINMAX);
Core.normalize(gHist, gHist, 0, histImage.rows()-20, Core.NORM_MINMAX);
Core.normalize(rHist, rHist, 0, histImage.rows()-20, Core.NORM_MINMAX);

float[] bHistData = new float[(int) (bHist.total() * bHist.channels())];
bHist.get(0, 0, bHistData);
System.out.println(Arrays.toString(bHistData));
float[] gHistData = new float[(int) (gHist.total() * gHist.channels())];
gHist.get(0, 0, gHistData);
float[] rHistData = new float[(int) (rHist.total() * rHist.channels())];
rHist.get(0, 0, rHistData);

for( int i = 1; i < histSize; i++ ) {
Imgproc.line(histImage, new Point(binW * (i - 1), histH - Math.round(bHistData[i - 1])),new Point(binW * (i), histH - Math.round(bHistData[i])), new Scalar(255, 0, 0), 2);
Imgproc.line(histImage, new Point(binW * (i - 1), histH - Math.round(gHistData[i - 1])),new Point(binW * (i), histH - Math.round(gHistData[i])), new Scalar(0, 255, 0), 2);
Imgproc.line(histImage, new Point(binW * (i - 1), histH - Math.round(rHistData[i - 1])),new Point(binW * (i), histH - Math.round(rHistData[i])), new Scalar(0, 0, 255), 2);
}

//imshow(histImage, "histImage");
HighGui.imshow("histImage", histImage);
HighGui.imshow("hello", hello);
HighGui.waitKey(0);
System.exit(0);

}



观察上面的直方图可以看到,blue通道与green通道的直方图偏向左边,而red通道的直方图偏向右边;如果我们显示单通道的图像,估计blue通道与green通道的图像偏黑,而red通道的图像偏白

opencv自带了运动目标检测的接口,这里测试一段视频检测效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub

BackgroundSubtractorMOG2 fgbg = Video.createBackgroundSubtractorMOG2();

Mat fgmask = new Mat();
//fgbg.apply(image, fgmask);

VideoCapture capture = new VideoCapture("images/target2.mp4");
if (!capture.isOpened()) {
System.err.println("--(!)Error opening video capture");
System.exit(0);
}

Mat frame = new Mat();
while (capture.read(frame)) {
if (frame.empty()) {
System.err.println("--(!) No captured frame -- Break!");
break;
}

//-- 3. Apply the classifier to the frame
fgbg.apply(frame, fgmask);

HighGui.imshow("原图", frame);

HighGui.imshow("检测目标", fgmask);


if (HighGui.waitKey(10) == 27) {
break;// escape
}
}

System.exit(0);
}

浏览到某英文网页上提供了基于opencv的C++和python版的二维码扫描器,其链接为https://www.learnopencv.com/opencv-qr-code-scanner-c-and-python/,不过貌似没有java版的,未免遗憾

这里本人依样画葫芦,仿造了java版本的二维码扫描器,方为完备

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

Mat image = imread("images/qrcode-feature.jpg");
QRCodeDetector detector = new QRCodeDetector();
Mat points = new Mat();
Mat straight_qrcode = new Mat();
String data = detector.detectAndDecode(image, points, straight_qrcode);

if (data.length() > 0) {
System.out.println("Decoded Data :" + data);

display(image, points);

// HighGui.imshow("points", points);
straight_qrcode.convertTo(straight_qrcode, CvType.CV_8UC3);

HighGui.imshow("Rectified QRCode", straight_qrcode);

HighGui.waitKey(0);
}

System.exit(0);
}

public static void display(Mat image, Mat points) {
int n = points.rows();
for (int i = 0; i < n; i++) {
Imgproc.line(image, new Point(points.get(i, 0)), new Point(points.get((i + 1) % n, 0)),
new Scalar(255, 0, 0), 3);
}
HighGui.imshow("Result", image);
}

测试输出

Decoded Data :http://LearnOpenCV.com

二维码定位:

以前在网上浏览到一篇英文文章,讲的是如何利用opencv实现图像目标尺寸检测,不过原文的实现代码是python;对于java程序员来说不方便调用,故本人采用java语言实现了同样的功能(由于精力及技术问题,延至今日才有java版本的实现),代码未有完善之处,如相关方法的参数值等,尚需后续补充

原文地址:https://www.pyimagesearch.com/2016/03/28/measuring-size-of-objects-in-an-image-with-opencv/
在此感谢原作者及网上相关参考文章(特别是雷锋网的翻译版本,貌似链接已经失效)

其基本思路是先获取图片中图像目标的轮廓,然后获取其旋转矩阵,并对旋转矩阵的坐标顺时针排序,然后获取其矩阵边框的中点坐标,最后是计算对称中点的欧氏距离(像素),最后再根据参照物的像素与英寸的比例计算实际距离

部分java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 图像目标尺寸检测
* @param args
*/
public static void main(String[] args) {

//Mat image = imread("images/test6.png");
Mat image = imread("images/example_01.png");
Mat gray = new Mat();
Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);

Imgproc.GaussianBlur(gray, gray, new Size(7,7), 0);

Mat edges = new Mat();
Imgproc.Canny(image, edges, 50, 150);
//Imgproc.Canny(image, edges,100.0, 200.0,3,true);

Mat kernel1=Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8,8), new Point(4,4));
Imgproc.dilate(edges, edges, kernel1 ,new Point(-1,-1),1);

Mat kernel=Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9,9), new Point(-1,-1));
Imgproc.erode(edges, edges, kernel,new Point(-1,-1),1);

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(edges.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
//……
}

最后效果如图:

我们发现,其中的测量对象的尺寸并不是百分之百准确,原文分析了两个原因:

1)图像的拍摄视角问题,不是绝对的90度角度

2)拍摄相机的相关参数校准问题

opencv官方自带了人脸识别的模型,这里测试一下效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 人脸识别测试
* @param args
*/
public static void main(String[] args) {
CascadeClassifier classifier = new CascadeClassifier("haarcascade_frontalface_alt.xml");

Mat image = Imgcodecs.imread("images/chuanpu.png");

MatOfRect faces = new MatOfRect();
classifier.detectMultiScale(image, faces);

Rect[] rects = faces.toArray();

System.out.println("识别人脸数:" + rects.length);
for (int i = 0; i < rects.length; i++) {
Imgproc.rectangle(image, new Point(rects[i].x, rects[i].y),
new Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 0, 255), 1);
Imgproc.putText(image, "Human", new Point(rects[i].x, rects[i].y), Imgproc.FONT_HERSHEY_PLAIN, 1.0,
new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, false);
}
imwrite("output/face2.png", image);
}

本文在边缘检测的基础上继续,即将上文边缘检测的结果(矩阵)输入,然后进一步发现轮廓并绘制
这里先将opencv库的加载设置为类的静态代码块,在相关方法代码体里面不再声明

1
2
3
4
5
6
7
8
static {		
try {
NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

下面是轮廓绘制的相关方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 发现轮廓
* @param image
* @param onBlank
* @return
*/
static List<MatOfPoint> find_contours(Mat image, boolean onBlank) {
Mat imageBW = new Mat();

Imgproc.cvtColor(image, imageBW, Imgproc.COLOR_BGR2GRAY);
Imgproc.Canny(imageBW,imageBW,100.0,300.0,3, true);

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imageBW, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
return contours;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static Scalar BLACK = new Scalar(0,0,0) ;
/**
* 绘制轮廓
* @param originalMat
* @param contours
* @param thickness
* @return
*/
static Mat draw_contours(Mat originalMat, List<MatOfPoint> contours, int thickness) {
Mat target =
new Mat(originalMat.height(), originalMat.width(), CvType.CV_8UC3, WHITE);

for (int i = 0; i < contours.size(); i++)
Imgproc.drawContours(target, contours, i, BLACK, thickness);

return target;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 发现及绘制轮廓
* @param args
*/
public static void main(String[] args) {

Mat kittens = imread("images/three_black_kittens.jpg");
List<MatOfPoint> contours = find_contours(kittens, true);

Mat target = draw_contours(kittens, contours, 7);
imwrite("output/kittens-contours-7.png", target);

Mat masked = mask_on_bg(target, "images/light-blue-gradient.jpg");
imwrite("output/kittens-masked.png", masked);

target = draw_contours(kittens, contours, 3);
imwrite("output/kittens-contours-3.png", target);
}

原图

处理后


下面是使用掩模的输出

1
2
3
4
5
6
7
static Mat mask_on_bg(Mat mask, String backgroundFilePath) {
Mat target = new Mat(mask.height(),mask.width(),CvType.CV_8UC3,WHITE);
Mat bg = imread(backgroundFilePath);
Imgproc.resize(bg, bg, target.size());
bg.copyTo(target, mask);
return target;
}

opencv是一个C++语言库,对于java程序员来说,貌似不是很友好;不过java程序员可以利用jni调用的方式来处理

for example:

1
2
3
4
5
6
7
8
9
10
public static void main1(String[] args) throws Exception {
NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat hello = Mat.eye(150, 150, CvType.CV_8SC3);
System.out.println(hello.dump());
hello.setTo(new Scalar(180,80,250));
Mat sub=hello.submat(0,50,0,50);
sub.setTo(new Scalar(0,0,100));
//imwrite("E:\\idea-workspace\\hellocv\\dev\\hello.png",hello);
//System.out.println(hello.dump());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 边缘检测算子
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat tools=Imgcodecs.imread("images/tools.jpg");
Imgproc.cvtColor(tools, tools, Imgproc.COLOR_RGB2GRAY);
Imgproc.Canny(tools, tools,100.0, 300.0,3,true);

Mat invetedTools=tools.clone();
bitwise_not(invetedTools, invetedTools);
Imgcodecs.imwrite("output/tools-04.png", invetedTools);
}


图像掩模

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static Scalar WHITE = new Scalar(255,255,255);
/**
* 图像掩模
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {

NativeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);

Mat kittens = imread("images/tools.jpg");

Imgproc.cvtColor(kittens, kittens, Imgproc.COLOR_RGB2GRAY);
Imgproc.Canny(kittens, kittens, 100.0, 300.0, 3, true);
bitwise_not(kittens, kittens);
// System.out.println(kittens.dump());

Mat target = new Mat(kittens.height(), kittens.width(), CvType.CV_8UC3, WHITE);
Mat bg = imread("images/light-blue-gradient.jpg");
Imgproc.resize(bg, bg, target.size());
bg.copyTo(target, kittens);

imwrite("output/kittens-03.png", target);
}