python隐藏cmd命令行窗口

在用pyinstaller打包后不想要后面的终端命令框,但是打包时加了-w或者–noconsole命令后会导致cmd程序不能运行从而出错。这个时候用subprocess可以解决该类问题。

import subprocess cmd = 'your command'res = subprocess.call(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

在用pyinstaller打包后不想要后面的终端命令框,但是打包时加了-w或者–noconsole命令后会导致cmd程序不能运行从而出错。这个时候用subprocess可以解决该类问题。

  1. import subprocess
  2. cmd = 'your command'
  3. res = subprocess.call(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
这样打包后出来的程序就不会出现命令框,而且也能够正常运行了。这样打包后出来的程序就不会出现命令框,而且也能够正常运行了。

深度学习小项目——图像风格迁移(基于Tensorflow)

基于神经网络的风格迁移算法 “A Neural Algorithm of Artistic Style” 最早由 Gatys 等人在 2015 年提出,随后发表在 CVPR 2016 上。斯坦福大学的 Justin Johnson(cs231n 课程的主讲人之一)给出了 Torch 实现 neural-style。除此之外,这篇文章的作者另外还建立了一个在线艺术风格迁移的网站,deepart.io。在介绍主要内容之前,先直观看下什么是艺术风格迁移,如图 1 所示,给定内容图像(第一行左边图像)以及风格图像(左下角图像)可以生成特定风格下的混合图像。网络多次运算后,人眼很难

图像内容和图像风格定义

艺术风格迁移的核心思想就是,可以从一副图像中提取出“风格 style”(比如梵高的夜空风格)以及“内容 content”(比如你能在画中看出河边有匹马)。你可以告诉机器,把 A 用 B 的风格再画一遍。但是怎么用数学语言具体定义风格和内容呢?在这里通过引入一个 VGG19 深度网络来具体阐述相关的含义。

VGG19深度网络

VGG 是 ImageNet2014 年的图像识别大赛识别定位组的冠军,几种不同深度的 VGG 网络结构如图 2 所示:

每一层神经网络都会利用上一层的输出来进一步提取更加复杂的特征,直到复杂到能被用来识别物体为止,所以每一层都可以被看做很多个局部特征的提取器。VGG19 在物体识别方面的精度甩了之前的算法一大截,之后的物体识别系统也基本都改用深度学习了。

因为 VGG19 的优秀表现,引起了很多兴趣和讨论,但是 VGG19 具体内部在做什么其实很难理解,因为每一个神经元内部参数只是一堆数字而已。每个神经元有几百个输入和几百个输出,一个一个去梳理清楚神经元和神经元之间的关系太难。于是有人想出来一种办法:虽然我们不知道神经元是怎么工作的,但是如果我们知道了它的激活条件,会不会能对理解神经网络更有帮助呢?于是他们编了一个程序,(用的方法叫 back propagation,和训练神经网络的方法一样,只是倒过来生成图片。)把每个神经元所对应的能激活它的图片找了出来,之前的那幅特征提取示意图就是这么生成的。

代码:

# -*- coding: utf-8 -*-# @Time    : 2019/2/21 18:03# @Author  : Chaucer_Gxm# @Email   : gxm4167235@163.com# @File    : Code_Tensorflow.py# @GitHub  : https://github.com/Chaucergit/Code-and-Algorithm# @blog    : https://blog.csdn.net/qq_24819773# @Software: PyCharmimport tensorflow as tfimport numpy as npimport scipy.ioimport scipy.miscimport osimport time  def the_current_time():    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(time.time()))))  CONTENT_IMG = 'flower.jpg'STYLE_IMG = 'style5.jpg'OUTPUT_DIR = 'Tensorflow_Picture2/' # 如果没有相应的文件夹就自动创建文件夹if not os.path.exists(OUTPUT_DIR):    os.mkdir(OUTPUT_DIR) IMAGE_W = 270IMAGE_H = 480COLOR_C = 3 NOSIE_RATIO = 0.7BETE = 5ALPHA = 100VGG_MODEL = 'imagenet-vgg-verydeep-19.mat'MEAN_VALUES = np.array([123.68, 116.779, 103.939]).reshape((1, 1, 1, 3))  def load_vgg_model(path):    vgg = scipy.io.loadmat(path)    vgg_layers = vgg['layers']     def _weights(layer, expected_layer_name):        W = vgg_layers[0][layer][0][0][2][0][0]        b = vgg_layers[0][layer][0][0][2][0][1]        layer_name = vgg_layers[0][layer][0][0][0][0]        assert layer_name == expected_layer_name        return W, b     def _conv2d_relu(prev_layer, layer, layer_name):        W, b = _weights(layer, layer_name)        W = tf.constant(W)        b = tf.constant(np.reshape(b, (b.size)))        return tf.nn.relu(tf.nn.conv2d(prev_layer, filter=W, strides=[1, 1, 1, 1], padding='SAME') + b)     def _avgpool(prev_layer):        return tf.nn.avg_pool(prev_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')     graph = {}    graph['input'] = tf.Variable(np.zeros((1, IMAGE_H, IMAGE_W, COLOR_C)), dtype='float32')    graph['conv1_1'] = _conv2d_relu(graph['input'], 0, 'conv1_1')    graph['conv1_2'] = _conv2d_relu(graph['conv1_1'], 2, 'conv1_2')    graph['avgpool1'] = _avgpool(graph['conv1_2'])    graph['conv2_1'] = _conv2d_relu(graph['avgpool1'], 5, 'conv2_1')    graph['conv2_2'] = _conv2d_relu(graph['conv2_1'], 7, 'conv2_2')    graph['avgpool2'] = _avgpool(graph['conv2_2'])    graph['conv3_1'] = _conv2d_relu(graph['avgpool2'], 10, 'conv3_1')    graph['conv3_2'] = _conv2d_relu(graph['conv3_1'], 12, 'conv3_2')    graph['conv3_3'] = _conv2d_relu(graph['conv3_2'], 14, 'conv3_3')    graph['conv3_4'] = _conv2d_relu(graph['conv3_3'], 16, 'conv3_4')    graph['avgpool3'] = _avgpool(graph['conv3_4'])    graph['conv4_1'] = _conv2d_relu(graph['avgpool3'], 19, 'conv4_1')    graph['conv4_2'] = _conv2d_relu(graph['conv4_1'], 21, 'conv4_2')    graph['conv4_3'] = _conv2d_relu(graph['conv4_2'], 23, 'conv4_3')    graph['conv4_4'] = _conv2d_relu(graph['conv4_3'], 25, 'conv4_4')    graph['avgpool4'] = _avgpool(graph['conv4_4'])    graph['conv5_1'] = _conv2d_relu(graph['avgpool4'], 28, 'conv5_1')    graph['conv5_2'] = _conv2d_relu(graph['conv5_1'], 30, 'conv5_2')    graph['conv5_3'] = _conv2d_relu(graph['conv5_2'], 32, 'conv5_3')    graph['conv5_4'] = _conv2d_relu(graph['conv5_3'], 34, 'conv5_4')    graph['avgpool5'] = _avgpool(graph['conv5_4'])    return graph  def content_loss_func(sess, model):    def _content_loss(p, x):        N = p.shape[3]        M = p.shape[1] * p.shape[2]        return (1/(4 * N * M)) * tf.reduce_sum(tf.pow(x-p, 2))    return _content_loss(sess.run(model['conv4_2']), model['conv4_2']) STYLE_LAYERS = [('conv1_1', 0.5), ('conv2_1', 1.0), ('conv3_1', 1.5), ('conv4_1', 3.0), ('conv5_1', 4.0)]  def style_loss_func(sess, model):    def _gram_matrix(F, N, M):        Ft = tf.reshape(F, (M, N))        return tf.matmul(tf.transpose(Ft), Ft)     def _style_loss(a, x):        N = a.shape[3]        M = a.shape[1] * a.shape[2]        A = _gram_matrix(a, N, M)        G = _gram_matrix(x, N, M)        return (1 / (4 * N ** 2 * M ** 2)) * tf.reduce_sum(tf.pow(G - A, 2))    return sum([_style_loss(sess.run(model[layer_name]), model[layer_name]) * w for layer_name, w in STYLE_LAYERS])  def generate_noise_image(content_image, noise_ratio=NOSIE_RATIO):    noise_image = np.random.uniform(-20, 20, (1, IMAGE_H, IMAGE_W, COLOR_C)).astype('float32')    input_image = noise_image * noise_ratio + content_image * (1 - noise_ratio)    return input_image  def load_image(path):    image = scipy.misc.imread(path)    image = scipy.misc.imresize(image, (IMAGE_H, IMAGE_W))    image = np.reshape(image, ((1, ) + image.shape))    image = image - MEAN_VALUES    return image  def save_image(path, image):    image = image + MEAN_VALUES    image = image[0]    image = np.clip(image, 0, 255).astype('uint8')    scipy.misc.imsave(path, image) the_current_time()  with tf.Session() as sess:    content_image = load_image(CONTENT_IMG)    style_image = load_image(STYLE_IMG)    model = load_vgg_model(VGG_MODEL)     input_image = generate_noise_image(content_image)    sess.run(tf.global_variables_initializer())     sess.run(model['input'].assign(content_image))    content_loss = content_loss_func(sess, model)     sess.run(model['input'].assign(style_image))    style_loss = style_loss_func(sess, model)     total_loss = BETE * content_loss + ALPHA * style_loss    optimizer = tf.train.AdamOptimizer(2.0)    train = optimizer.minimize(total_loss)     sess.run(tf.global_variables_initializer())    sess.run(model['input'].assign(input_image))     ITERATIONS = 2000    for i in range(ITERATIONS):        sess.run(train)        if i % 100 == 0:            output_image = sess.run(model['input'])            the_current_time()            print('Iteration %d' % i)            print('Cost: ', sess.run(total_loss))             save_image(os.path.join(OUTPUT_DIR, 'output_%d.jpg' % i), output_image)

执行前效果:

执行后的效果:


基于神经网络的图像风格迁移论文链接:

 深度学习小项目——图像风格迁移(基于Tensorflow)

基于神经网络的风格迁移算法 “A Neural Algorithm of Artistic Style” 最早由 Gatys 等人在 2015 年提出,随后发表在 CVPR 2016 上。斯坦福大学的 Justin Johnson(cs231n 课程的主讲人之一)给出了 Torch 实现 neural-style。除此之外,这篇文章的作者另外还建立了一个在线艺术风格迁移的网站,deepart.io。在介绍主要内容之前,先直观看下什么是艺术风格迁移,如图 1 所示,给定内容图像(第一行左边图像)以及风格图像(左下角图像)可以生成特定风格下的混合图像。网络多次运算后,人眼很难判断出该图像是否为梵高或者毕加索的真迹。

图像内容和图像风格定义

艺术风格迁移的核心思想就是,可以从一副图像中提取出“风格 style”(比如梵高的夜空风格)以及“内容 content”(比如你能在画中看出河边有匹马)。你可以告诉机器,把 A 用 B 的风格再画一遍。但是怎么用数学语言具体定义风格和内容呢?在这里通过引入一个 VGG19 深度网络来具体阐述相关的含义。 

VGG19深度网络

VGG 是 ImageNet2014 年的图像识别大赛识别定位组的冠军,几种不同深度的 VGG 网络结构如图 2 所示:

 

每一层神经网络都会利用上一层的输出来进一步提取更加复杂的特征,直到复杂到能被用来识别物体为止,所以每一层都可以被看做很多个局部特征的提取器。VGG19 在物体识别方面的精度甩了之前的算法一大截,之后的物体识别系统也基本都改用深度学习了。因为 VGG19 的优秀表现,引起了很多兴趣和讨论,但是 VGG19 具体内部在做什么其实很难理解,因为每一个神经元内部参数只是一堆数字而已。每个神经元有几百个输入和几百个输出,一个一个去梳理清楚神经元和神经元之间的关系太难。于是有人想出来一种办法:虽然我们不知道神经元是怎么工作的,但是如果我们知道了它的激活条件,会不会能对理解神经网络更有帮助呢?于是他们编了一个程序,(用的方法叫 back propagation,和训练神经网络的方法一样,只是倒过来生成图片。)把每个神经元所对应的能激活它的图片找了出来,之前的那幅特征提取示意图就是这么生成的。

代码:

  1. # -*- coding: utf-8 -*-
  2. # @Time : 2019/2/21 18:03
  3. # @Author : Chaucer_Gxm
  4. # @Email : gxm4167235@163.com
  5. # @File : Code_Tensorflow.py
  6. # @GitHub : https://github.com/Chaucergit/Code-and-Algorithm
  7. # @blog : https://blog.csdn.net/qq_24819773
  8. # @Software: PyCharm
  9. import tensorflow as tf
  10. import numpy as np
  11. import scipy.io
  12. import scipy.misc
  13. import os
  14. import time
  15. def the_current_time():
  16. print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(time.time()))))
  17. CONTENT_IMG = 'flower.jpg'
  18. STYLE_IMG = 'style5.jpg'
  19. OUTPUT_DIR = 'Tensorflow_Picture2/'
  20. # 如果没有相应的文件夹就自动创建文件夹
  21. if not os.path.exists(OUTPUT_DIR):
  22. os.mkdir(OUTPUT_DIR)
  23. IMAGE_W = 270
  24. IMAGE_H = 480
  25. COLOR_C = 3
  26. NOSIE_RATIO = 0.7
  27. BETE = 5
  28. ALPHA = 100
  29. VGG_MODEL = 'imagenet-vgg-verydeep-19.mat'
  30. MEAN_VALUES = np.array([123.68, 116.779, 103.939]).reshape((1, 1, 1, 3))
  31. def load_vgg_model(path):
  32. vgg = scipy.io.loadmat(path)
  33. vgg_layers = vgg['layers']
  34. def _weights(layer, expected_layer_name):
  35. W = vgg_layers[0][layer][0][0][2][0][0]
  36. b = vgg_layers[0][layer][0][0][2][0][1]
  37. layer_name = vgg_layers[0][layer][0][0][0][0]
  38. assert layer_name == expected_layer_name
  39. return W, b
  40. def _conv2d_relu(prev_layer, layer, layer_name):
  41. W, b = _weights(layer, layer_name)
  42. W = tf.constant(W)
  43. b = tf.constant(np.reshape(b, (b.size)))
  44. return tf.nn.relu(tf.nn.conv2d(prev_layer, filter=W, strides=[1, 1, 1, 1], padding='SAME') + b)
  45. def _avgpool(prev_layer):
  46. return tf.nn.avg_pool(prev_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  47. graph = {}
  48. graph['input'] = tf.Variable(np.zeros((1, IMAGE_H, IMAGE_W, COLOR_C)), dtype='float32')
  49. graph['conv1_1'] = _conv2d_relu(graph['input'], 0, 'conv1_1')
  50. graph['conv1_2'] = _conv2d_relu(graph['conv1_1'], 2, 'conv1_2')
  51. graph['avgpool1'] = _avgpool(graph['conv1_2'])
  52. graph['conv2_1'] = _conv2d_relu(graph['avgpool1'], 5, 'conv2_1')
  53. graph['conv2_2'] = _conv2d_relu(graph['conv2_1'], 7, 'conv2_2')
  54. graph['avgpool2'] = _avgpool(graph['conv2_2'])
  55. graph['conv3_1'] = _conv2d_relu(graph['avgpool2'], 10, 'conv3_1')
  56. graph['conv3_2'] = _conv2d_relu(graph['conv3_1'], 12, 'conv3_2')
  57. graph['conv3_3'] = _conv2d_relu(graph['conv3_2'], 14, 'conv3_3')
  58. graph['conv3_4'] = _conv2d_relu(graph['conv3_3'], 16, 'conv3_4')
  59. graph['avgpool3'] = _avgpool(graph['conv3_4'])
  60. graph['conv4_1'] = _conv2d_relu(graph['avgpool3'], 19, 'conv4_1')
  61. graph['conv4_2'] = _conv2d_relu(graph['conv4_1'], 21, 'conv4_2')
  62. graph['conv4_3'] = _conv2d_relu(graph['conv4_2'], 23, 'conv4_3')
  63. graph['conv4_4'] = _conv2d_relu(graph['conv4_3'], 25, 'conv4_4')
  64. graph['avgpool4'] = _avgpool(graph['conv4_4'])
  65. graph['conv5_1'] = _conv2d_relu(graph['avgpool4'], 28, 'conv5_1')
  66. graph['conv5_2'] = _conv2d_relu(graph['conv5_1'], 30, 'conv5_2')
  67. graph['conv5_3'] = _conv2d_relu(graph['conv5_2'], 32, 'conv5_3')
  68. graph['conv5_4'] = _conv2d_relu(graph['conv5_3'], 34, 'conv5_4')
  69. graph['avgpool5'] = _avgpool(graph['conv5_4'])
  70. return graph
  71. def content_loss_func(sess, model):
  72. def _content_loss(p, x):
  73. N = p.shape[3]
  74. M = p.shape[1] * p.shape[2]
  75. return (1/(4 * N * M)) * tf.reduce_sum(tf.pow(x-p, 2))
  76. return _content_loss(sess.run(model['conv4_2']), model['conv4_2'])
  77. STYLE_LAYERS = [('conv1_1', 0.5), ('conv2_1', 1.0), ('conv3_1', 1.5), ('conv4_1', 3.0), ('conv5_1', 4.0)]
  78. def style_loss_func(sess, model):
  79. def _gram_matrix(F, N, M):
  80. Ft = tf.reshape(F, (M, N))
  81. return tf.matmul(tf.transpose(Ft), Ft)
  82. def _style_loss(a, x):
  83. N = a.shape[3]
  84. M = a.shape[1] * a.shape[2]
  85. A = _gram_matrix(a, N, M)
  86. G = _gram_matrix(x, N, M)
  87. return (1 / (4 * N ** 2 * M ** 2)) * tf.reduce_sum(tf.pow(G - A, 2))
  88. return sum([_style_loss(sess.run(model[layer_name]), model[layer_name]) * w for layer_name, w in STYLE_LAYERS])
  89. def generate_noise_image(content_image, noise_ratio=NOSIE_RATIO):
  90. noise_image = np.random.uniform(-20, 20, (1, IMAGE_H, IMAGE_W, COLOR_C)).astype('float32')
  91. input_image = noise_image * noise_ratio + content_image * (1 - noise_ratio)
  92. return input_image
  93. def load_image(path):
  94. image = scipy.misc.imread(path)
  95. image = scipy.misc.imresize(image, (IMAGE_H, IMAGE_W))
  96. image = np.reshape(image, ((1, ) + image.shape))
  97. image = image - MEAN_VALUES
  98. return image
  99. def save_image(path, image):
  100. image = image + MEAN_VALUES
  101. image = image[0]
  102. image = np.clip(image, 0, 255).astype('uint8')
  103. scipy.misc.imsave(path, image)
  104. the_current_time()
  105. with tf.Session() as sess:
  106. content_image = load_image(CONTENT_IMG)
  107. style_image = load_image(STYLE_IMG)
  108. model = load_vgg_model(VGG_MODEL)
  109. input_image = generate_noise_image(content_image)
  110. sess.run(tf.global_variables_initializer())
  111. sess.run(model['input'].assign(content_image))
  112. content_loss = content_loss_func(sess, model)
  113. sess.run(model['input'].assign(style_image))
  114. style_loss = style_loss_func(sess, model)
  115. total_loss = BETE * content_loss + ALPHA * style_loss
  116. optimizer = tf.train.AdamOptimizer(2.0)
  117. train = optimizer.minimize(total_loss)
  118. sess.run(tf.global_variables_initializer())
  119. sess.run(model['input'].assign(input_image))
  120. ITERATIONS = 2000
  121. for i in range(ITERATIONS):
  122. sess.run(train)
  123. if i % 100 == 0:
  124. output_image = sess.run(model['input'])
  125. the_current_time()
  126. print('Iteration %d' % i)
  127. print('Cost: ', sess.run(total_loss))
  128. save_image(os.path.join(OUTPUT_DIR, 'output_%d.jpg' % i), output_image)

执行前效果:

执行后的效果:


基于神经网络的图像风格迁移论文链接:

**Texture synthesis using convolutional neural networks***A neural algorithm of artistic style*Combining Markov Random Fields and Convolutional Neural Networks for Image Synthesis*Texture networks: Feed-forward synthesis of textures and stylized imagesA Learned Representation For Artistic StyleFast Patch-based Style Transfer of Arbitrary Style*Arbitrary Style Transfer in Real-time with Adaptive Instance NormalizationVisual Attribute Transfer through Deep Image Analogy参考博文的链接:https://www.imooc.com/article/details/id/32660

**Texture synthesis using convolutional neural networks
***A neural algorithm of artistic style
*Combining Markov Random Fields and Convolutional Neural Networks for Image Synthesis
*Texture networks: Feed-forward synthesis of textures and stylized images
A Learned Representation For Artistic Style
Fast Patch-based Style Transfer of Arbitrary Style
*Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization
Visual Attribute Transfer through Deep Image Analogy
参考博文的链接:https://www.imooc.com/article/details/id/32660

moviepy教程

一、功能简介

前段时间需要对多个视频进行合并,还需要对一个视频按需求进行截切成多个视频,然而网上虽然有现成的工具。

但是大部分工具都带有第三方logo,这会影响视频的使用,而作者正好在学习python,为什么不自己搞一个类似

的简易版的工具呢?因此一个简单的视频合并/视频截切的工具就此诞生了。

二、视频合并

复制代码
 1 import imageio
 2 imageio.plugins.ffmpeg.download()
 3 import sys,os
 4 from PyQt5.QtCore import *
 5 from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,QLabel,
 6                              QInputDialog, QApplication,QFileDialog)
 7 from moviepy.video.io.VideoFileClip  import VideoFileClip
 8 from moviepy.video.compositing.concatenate import concatenate_videoclips
 9 from natsort import natsorted
10 
11 class Example(QWidget):
12     def __init__(self):
13         super().__init__()
14 
15         self.initUI()
16 
17     def initUI(self):
18         # 源文件选择按钮和选择编辑框
19         self.source_btn = QPushButton('source', self)
20         self.source_btn.move(30, 30)
21         self.source_btn.resize(60,30)
22         self.source_btn.clicked.connect(self.select_source)
23         self.source_le = QLineEdit(self)
24         self.source_le.move(120, 30)
25         self.source_le.resize(250,30)
26 
27         # 存储文件选择按钮和选择编辑框
28         self.target_btn = QPushButton('target', self)
29         self.target_btn.move(30, 90)
30         self.target_btn.resize(60, 30)
31         self.target_btn.clicked.connect(self.select_target)
32         self.target_le = QLineEdit(self)
33         self.target_le.move(120, 90)
34         self.target_le.resize(250, 30)
35 
36         # 保存按钮,调取数据增加函数等
37         self.save_btn = QPushButton('save',self)
38         self.save_btn.move(30, 150)
39         self.save_btn.resize(150, 30)
40         self.save_btn.clicked.connect(self.addNum)
41 
42         # 退出按钮,点击按钮退出整个程序
43         self.cancle_btn = QPushButton('cancle',self)
44         self.cancle_btn.move(220, 150)
45         self.cancle_btn.resize(150, 30)
46         self.cancle_btn.clicked.connect(QCoreApplication.quit)
47 
48         # 执行成功返回值显示位置设置
49         self.result_le = QLabel(self)
50         self.result_le.move(30, 210)
51         self.result_le.resize(340, 30)
52 
53         # 技术支持框
54         self.sourceLabel = QLabel(self)
55         self.sourceLabel.move(30, 360)
56         self.sourceLabel.resize(340, 30)
57         self.sourceLabel.setText("Technical support:Azrael ")
58         self.sourceLabel.setStyleSheet("color:blue;font-size:18px")
59         self.sourceLabel.setAlignment(Qt.AlignCenter)
60 
61         # 整体界面设置
62         self.setGeometry(400, 400, 400, 400)
63         self.setWindowTitle('video binding')
64         self.show()
65 
66     # 打开的视频文件路径
67     def select_source(self):
68         source = QFileDialog.getExistingDirectory(self, "select the video directory", "C:/")
69         self.source_le.setText(str(source))
70 
71     # 保存的视频文件名称,要写上后缀名
72     def select_target(self):
73         target,fileType = QFileDialog.getSaveFileName(self, "select the save directory", "C:/")
74         self.target_le.setText(str(target))
75 
76     def addNum(self):
77         source = self.source_le.text().strip()#获取源视频文件存储地址
78         target = self.target_le.text().strip()#获取合成视频保存地址
79         video_list = []#定义加载后的视频存储列表
80         for root, dirs, files in os.walk(source):
81             files = natsorted(files)#按1,2,10类似规则对视频文件进行排序
82             for file in files:
83                 if os.path.splitext(file)[1] == ".mp4":#判断视频文件格式是否为.mp4
84                     file_path = os.path.join(source, file)#粘合完整视频路径
85                     video = VideoFileClip(file_path)#加载视频
86                     video_list.append(video)#将加载完后的视频加入列表
87         final_clip = concatenate_videoclips(video_list)#进行视频合并
88         final_clip.to_videofile(target, fps=24, remove_temp=True)#将合并后的视频输出
89         self.result_le.setText("ok!")#输出文件后界面返回OK
90         self.result_le.setStyleSheet("color:red;font-size:40px")#设置OK颜色为红色,大小为四十像素
91         self.result_le.setAlignment(Qt.AlignCenter)#OK在指定框内居中
92 
93 
94 if __name__ == '__main__':
95     app = QApplication(sys.argv)
96     ex = Example()
97     sys.exit(app.exec_())

视频合并

复制代码

三、视频剪切

复制代码
  1 #Author:Azrael
  2 import imageio
  3 imageio.plugins.ffmpeg.download()
  4 import win_unicode_console
  5 win_unicode_console.enable()
  6 import sys,os
  7 from PyQt5.QtCore import *
  8 from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,QLabel,
  9                               QApplication,QFileDialog)
 10 from moviepy.video.io.VideoFileClip  import VideoFileClip
 11 
 12 
 13 class login(QWidget):
 14     def __init__(self):
 15         super(login,self).__init__()
 16         self.initUI()
 17 
 18     def initUI(self):
 19         #源文件选择按钮和选择编辑框
 20         self.source_btn = QPushButton('source', self)
 21         self.source_btn.move(30, 30)
 22         self.source_btn.resize(60,30)
 23         self.source_btn.clicked.connect(self.select_source)
 24         self.source_le = QLineEdit(self)
 25         self.source_le.move(120, 30)
 26         self.source_le.resize(250,30)
 27 
 28         # 存储文件选择按钮和选择编辑框
 29         self.target_btn = QPushButton('target', self)
 30         self.target_btn.move(30, 90)
 31         self.target_btn.resize(60, 30)
 32         self.target_btn.clicked.connect(self.select_target)
 33         self.target_le = QLineEdit(self)
 34         self.target_le.move(120, 90)
 35         self.target_le.resize(250, 30)
 36 
 37         #截切开始时间输入框和提示
 38         self.startLabel = QLabel(self)
 39         self.startLabel.move(30, 150)
 40         self.startLabel.resize(60,30)
 41         self.startLabel.setText("stat_time")
 42         self.start_le = QLineEdit(self)
 43         self.start_le.move(120,150)
 44         self.start_le.resize(50,30)
 45 
 46         # 截切结束时间输入框和提示
 47         self.stopLabel = QLabel(self)
 48         self.stopLabel.move(230, 150)
 49         self.stopLabel.resize(60,30)
 50         self.stopLabel.setText("stop_time")
 51         self.stop_le = QLineEdit(self)
 52         self.stop_le.move(320,150)
 53         self.stop_le.resize(50,30)
 54 
 55         #保存按钮,调取数据增加函数等
 56         self.save_btn = QPushButton('save',self)
 57         self.save_btn.move(30, 210)
 58         self.save_btn.resize(140, 30)
 59         self.save_btn.clicked.connect(self.addNum)
 60 
 61         #退出按钮,点击按钮退出整个程序
 62         self.cancle_btn = QPushButton('cancle',self)
 63         self.cancle_btn.move(230, 210)
 64         self.cancle_btn.resize(140, 30)
 65         self.cancle_btn.clicked.connect(QCoreApplication.quit)
 66 
 67         #执行成功返回值显示位置设置
 68         self.result_le = QLabel(self)
 69         self.result_le.move(30, 270)
 70         self.result_le.resize(340, 30)
 71 
 72         #技术支持框
 73         self.sourceLabel = QLabel(self)
 74         self.sourceLabel.move(30, 360)
 75         self.sourceLabel.resize(340, 30)
 76         self.sourceLabel.setText("Technical support:Azrael ")
 77         self.sourceLabel.setStyleSheet("color:blue;font-size:18px")
 78         self.sourceLabel.setAlignment(Qt.AlignCenter)
 79 
 80         #整体界面设置
 81         self.setGeometry(400, 400, 400, 400)
 82         self.setWindowTitle('video binding')#设置界面标题名
 83         self.show()
 84 
 85     # 打开的视频文件名称
 86     def select_source(self):
 87         target,fileType = QFileDialog.getOpenFileName(self, "select the source file", "C:/")
 88         self.source_le.setText(str(target))
 89     #保存的视频文件名称,要写上后缀名
 90     def select_target(self):
 91         target,fileType = QFileDialog.getSaveFileName(self, "select the save file", "C:/")
 92         self.target_le.setText(str(target))
 93 
 94 
 95     def addNum(self):
 96         source = self.source_le.text().strip()#获取需要剪切的文件
 97         target = self.target_le.text().strip()#获取剪切后视频保存的文件
 98         start_time = self.start_le.text().strip()#获取开始剪切时间
 99         stop_time = self.stop_le.text().strip()#获取剪切的结束时间
100         video = VideoFileClip(source)#视频文件加载
101         video = video.subclip(int(start_time), int(stop_time))#执行剪切操作
102         video.to_videofile(target, fps=20, remove_temp=True)#输出文件
103         self.result_le.setText("ok!")#输出文件后界面返回OK
104         self.result_le.setStyleSheet("color:red;font-size:40px")#设置OK颜色为红色,大小为四十像素
105         self.result_le.setAlignment(Qt.AlignCenter)#OK在指定框内居中
106 
107 if __name__=="__main__":
108     app = QApplication(sys.argv)
109     ex = login()
110     sys.exit(app.exec_())

一、功能简介

前段时间需要对多个视频进行合并,还需要对一个视频按需求进行截切成多个视频,然而网上虽然有现成的工具。但是大部分工具都带有第三方logo,这会影响视频的使用,而作者正好在学习python,为什么不自己搞一个类似的简易版的工具呢?因此一个简单的视频合并/视频截切的工具就此诞生了。 二、视频合并

复制代码
 1 import imageio  2 imageio.plugins.ffmpeg.download()  3 import sys,os  4 from PyQt5.QtCore import *  5 from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,QLabel,  6                              QInputDialog, QApplication,QFileDialog)  7 from moviepy.video.io.VideoFileClip  import VideoFileClip  8 from moviepy.video.compositing.concatenate import concatenate_videoclips  9 from natsort import natsorted 10  11 class Example(QWidget): 12     def __init__(self): 13         super().__init__() 14  15         self.initUI() 16  17     def initUI(self): 18         # 源文件选择按钮和选择编辑框 19         self.source_btn = QPushButton('source', self) 20         self.source_btn.move(30, 30) 21         self.source_btn.resize(60,30) 22         self.source_btn.clicked.connect(self.select_source) 23         self.source_le = QLineEdit(self) 24         self.source_le.move(120, 30) 25         self.source_le.resize(250,30) 26  27         # 存储文件选择按钮和选择编辑框 28         self.target_btn = QPushButton('target', self) 29         self.target_btn.move(30, 90) 30         self.target_btn.resize(60, 30) 31         self.target_btn.clicked.connect(self.select_target) 32         self.target_le = QLineEdit(self) 33         self.target_le.move(120, 90) 34         self.target_le.resize(250, 30) 35  36         # 保存按钮,调取数据增加函数等 37         self.save_btn = QPushButton('save',self) 38         self.save_btn.move(30, 150) 39         self.save_btn.resize(150, 30) 40         self.save_btn.clicked.connect(self.addNum) 41  42         # 退出按钮,点击按钮退出整个程序 43         self.cancle_btn = QPushButton('cancle',self) 44         self.cancle_btn.move(220, 150) 45         self.cancle_btn.resize(150, 30) 46         self.cancle_btn.clicked.connect(QCoreApplication.quit) 47  48         # 执行成功返回值显示位置设置 49         self.result_le = QLabel(self) 50         self.result_le.move(30, 210) 51         self.result_le.resize(340, 30) 52  53         # 技术支持框 54         self.sourceLabel = QLabel(self) 55         self.sourceLabel.move(30, 360) 56         self.sourceLabel.resize(340, 30) 57         self.sourceLabel.setText("Technical support:Azrael ") 58         self.sourceLabel.setStyleSheet("color:blue;font-size:18px") 59         self.sourceLabel.setAlignment(Qt.AlignCenter) 60  61         # 整体界面设置 62         self.setGeometry(400, 400, 400, 400) 63         self.setWindowTitle('video binding') 64         self.show() 65  66     # 打开的视频文件路径 67     def select_source(self): 68         source = QFileDialog.getExistingDirectory(self, "select the video directory", "C:/") 69         self.source_le.setText(str(source)) 70  71     # 保存的视频文件名称,要写上后缀名 72     def select_target(self): 73         target,fileType = QFileDialog.getSaveFileName(self, "select the save directory", "C:/") 74         self.target_le.setText(str(target)) 75  76     def addNum(self): 77         source = self.source_le.text().strip()#获取源视频文件存储地址 78         target = self.target_le.text().strip()#获取合成视频保存地址 79         video_list = []#定义加载后的视频存储列表 80         for root, dirs, files in os.walk(source): 81             files = natsorted(files)#按1,2,10类似规则对视频文件进行排序 82             for file in files: 83                 if os.path.splitext(file)[1] == ".mp4":#判断视频文件格式是否为.mp4 84                     file_path = os.path.join(source, file)#粘合完整视频路径 85                     video = VideoFileClip(file_path)#加载视频 86                     video_list.append(video)#将加载完后的视频加入列表 87         final_clip = concatenate_videoclips(video_list)#进行视频合并 88         final_clip.to_videofile(target, fps=24, remove_temp=True)#将合并后的视频输出 89         self.result_le.setText("ok!")#输出文件后界面返回OK 90         self.result_le.setStyleSheet("color:red;font-size:40px")#设置OK颜色为红色,大小为四十像素 91         self.result_le.setAlignment(Qt.AlignCenter)#OK在指定框内居中 92  93  94 if __name__ == '__main__': 95     app = QApplication(sys.argv) 96     ex = Example() 97     sys.exit(app.exec_())
视频合并
复制代码

 三、视频剪切

复制代码
  1 #Author:Azrael   2 import imageio   3 imageio.plugins.ffmpeg.download()   4 import win_unicode_console   5 win_unicode_console.enable()   6 import sys,os   7 from PyQt5.QtCore import *   8 from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,QLabel,   9                               QApplication,QFileDialog)  10 from moviepy.video.io.VideoFileClip  import VideoFileClip  11   12   13 class login(QWidget):  14     def __init__(self):  15         super(login,self).__init__()  16         self.initUI()  17   18     def initUI(self):  19         #源文件选择按钮和选择编辑框  20         self.source_btn = QPushButton('source', self)  21         self.source_btn.move(30, 30)  22         self.source_btn.resize(60,30)  23         self.source_btn.clicked.connect(self.select_source)  24         self.source_le = QLineEdit(self)  25         self.source_le.move(120, 30)  26         self.source_le.resize(250,30)  27   28         # 存储文件选择按钮和选择编辑框  29         self.target_btn = QPushButton('target', self)  30         self.target_btn.move(30, 90)  31         self.target_btn.resize(60, 30)  32         self.target_btn.clicked.connect(self.select_target)  33         self.target_le = QLineEdit(self)  34         self.target_le.move(120, 90)  35         self.target_le.resize(250, 30)  36   37         #截切开始时间输入框和提示  38         self.startLabel = QLabel(self)  39         self.startLabel.move(30, 150)  40         self.startLabel.resize(60,30)  41         self.startLabel.setText("stat_time")  42         self.start_le = QLineEdit(self)  43         self.start_le.move(120,150)  44         self.start_le.resize(50,30)  45   46         # 截切结束时间输入框和提示  47         self.stopLabel = QLabel(self)  48         self.stopLabel.move(230, 150)  49         self.stopLabel.resize(60,30)  50         self.stopLabel.setText("stop_time")  51         self.stop_le = QLineEdit(self)  52         self.stop_le.move(320,150)  53         self.stop_le.resize(50,30)  54   55         #保存按钮,调取数据增加函数等  56         self.save_btn = QPushButton('save',self)  57         self.save_btn.move(30, 210)  58         self.save_btn.resize(140, 30)  59         self.save_btn.clicked.connect(self.addNum)  60   61         #退出按钮,点击按钮退出整个程序  62         self.cancle_btn = QPushButton('cancle',self)  63         self.cancle_btn.move(230, 210)  64         self.cancle_btn.resize(140, 30)  65         self.cancle_btn.clicked.connect(QCoreApplication.quit)  66   67         #执行成功返回值显示位置设置  68         self.result_le = QLabel(self)  69         self.result_le.move(30, 270)  70         self.result_le.resize(340, 30)  71   72         #技术支持框  73         self.sourceLabel = QLabel(self)  74         self.sourceLabel.move(30, 360)  75         self.sourceLabel.resize(340, 30)  76         self.sourceLabel.setText("Technical support:Azrael ")  77         self.sourceLabel.setStyleSheet("color:blue;font-size:18px")  78         self.sourceLabel.setAlignment(Qt.AlignCenter)  79   80         #整体界面设置  81         self.setGeometry(400, 400, 400, 400)  82         self.setWindowTitle('video binding')#设置界面标题名  83         self.show()  84   85     # 打开的视频文件名称  86     def select_source(self):  87         target,fileType = QFileDialog.getOpenFileName(self, "select the source file", "C:/")  88         self.source_le.setText(str(target))  89     #保存的视频文件名称,要写上后缀名  90     def select_target(self):  91         target,fileType = QFileDialog.getSaveFileName(self, "select the save file", "C:/")  92         self.target_le.setText(str(target))  93   94   95     def addNum(self):  96         source = self.source_le.text().strip()#获取需要剪切的文件  97         target = self.target_le.text().strip()#获取剪切后视频保存的文件  98         start_time = self.start_le.text().strip()#获取开始剪切时间  99         stop_time = self.stop_le.text().strip()#获取剪切的结束时间 100         video = VideoFileClip(source)#视频文件加载 101         video = video.subclip(int(start_time), int(stop_time))#执行剪切操作 102         video.to_videofile(target, fps=20, remove_temp=True)#输出文件 103         self.result_le.setText("ok!")#输出文件后界面返回OK 104         self.result_le.setStyleSheet("color:red;font-size:40px")#设置OK颜色为红色,大小为四十像素 105         self.result_le.setAlignment(Qt.AlignCenter)#OK在指定框内居中 106  107 if __name__=="__main__": 108     app = QApplication(sys.argv) 109     ex = login() 110     sys.exit(app.exec_())
视频剪切视频剪切

Python实现12306自动抢票

市场上很多火车票抢票软件大家应该非常熟悉,但很少有人研究具体是怎么实现的,所以觉得很神秘,其实很简单。下面使用Python模拟抢票程序,给大家揭秘抢票到底是怎么回事。

该代码仅供参考,主要用于大家沟通交流,禁止用于商业用途。

具体代码如下,可以修改成自己的12306用户名账号:

用 Python 代码自动抢火车票

准备工具

  • 12306网站用户名和密码
  • Python
  • chrome浏览器及下载chromedriver
  • 下载Python代码,位于:https://github.com/ppy2790/tickets

代码用的Python+Splinter开发,Splinter是一个使用Python开发的开源Web应用测试工具,它可以帮你实现自动浏览站点和与其进行交互。Splinter官网

http://splinter.readthedocs.io/en/latest/ 。Splinter执行的时候会自动打开你指定的浏览器,访问指定的URL。然后你所开发的模拟的任何行为,都会自动完成,你只需要坐在电脑面前,像看电影一样看着屏幕上各种动作自动完成然后收集结果即可。

了解原理

找到相应URL,找到控件模拟登录、查询、订票操作。关键是找到控件名称,难点是起始地不是直接输入的页面值,需要在cookie中查出。

  • 12306查询URL:
  • https://kyfw.12306.cn/otn/leftTicket/init
  • 12306登录URL:
  • https://kyfw.12306.cn/otn/login/init
  • 我的12306URL:
  • https://kyfw.12306.cn/otn/index/initMy12306
  • 购票确认URL:
  • https://kyfw.12306.cn/otn/confirmPassenger/initDc

Python代码打开URL,找到控件填充值:

找到用户名密码控件名

找到起始地控件名

确定起始地的值,方法Chrome浏览器中的“检查”功能(按F12),Network —> Cookies中找到:

用 Python 代码自动抢火车票

cookie中起始地的值

拷贝起始地的cookie值,我把几个常用的城市拷出来,放到了字典中:

用 Python 代码自动抢火车票

查询车票代码:

用 Python 代码自动抢火车票

其实,你只需要运行代码:

用 Python 代码自动抢火车票

当然,还需要手动点一下的还是万恶的12306验证码,抢到票后确认支付就行啦。

用 Python 代码自动抢火车票

抢票进行中

用 Python 代码自动抢火车票

抢票成功!

Python之os与sys详解

os与sys模块的官方解释如下:

os: This module provides a portable way of using operating system dependent functionality.

这个模块提供了一种方便的使用操作系统函数的方法。

sys: This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter.

这个模块可供访问由解释器使用或维护的变量和与解释器进行交互的函数。

总结:

os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;

sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

os 常用方法

os.remove(‘path/filename’) 删除文件

os.rename(oldname, newname) 重命名文件

os.walk() 生成目录树下的所有文件名

os.chdir(‘dirname’) 改变目录

os.mkdir/makedirs(‘dirname’) 创建目录/多层目录

os.rmdir/removedirs(‘dirname’) 删除目录/多层目录

os.listdir(‘dirname’) 列出指定目录的文件

os.getcwd() 取得当前工作目录

os.chmod() 改变目录权限

os.path.basename(‘path/filename’) 去掉目录路径,返回文件名

os.path.dirname(‘path/filename’) 去掉文件名,返回目录路径

os.path.join(path1[,path2[,…]]) 将分离的各部分组合成一个路径名

os.path.split(‘path’) 返回( dirname(), basename())元组

os.path.splitext() 返回 (filename, extension) 元组

os.path.getatime\ctime\mtime 分别返回最近访问、创建、修改时间

os.path.getsize() 返回文件大小

os.path.exists() 是否存在

os.path.isabs() 是否为绝对路径

os.path.isdir() 是否为目录

os.path.isfile() 是否为文件

sys 常用方法

sys.argv 命令行参数List,第一个元素是程序本身路径

sys.modules.keys() 返回所有已经导入的模块列表

sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息

sys.exit(n) 退出程序,正常退出时exit(0)

sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0

sys.version 获取Python解释程序的版本信息

sys.maxint 最大的Int值

sys.maxunicode 最大的Unicode值

sys.modules 返回系统导入的模块字段,key是模块名,value是模块

sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值

sys.platform 返回操作系统平台名称

sys.stdout 标准输出

sys.stdin 标准输入

sys.stderr 错误输出

sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息

sys.exec_prefix 返回平台独立的python文件安装的位置

sys.byteorder 本地字节规则的指示器,big-endian平台的值是’big’,little-endian平台的值是’little’

sys.copyright 记录python版权相关的东西

sys.api_version 解释器的C的API版本

Python中sys.argv[0]的用法

1、sys.argv 是获取运行python文件的时候命令行参数,且以list形式存储参数

2、sys.argv[0]表示代码本身文件路径

特别注意:接下来这个例子,sys.argv[0]就应该是文件名test.py,不应包含路径!!!

下面我们通过一个极简单的test.py程序的运行结果来说明它的用法

import sysa=sys.argv[0]print(a)

将test.py保存在c盘的根目录下。

在程序中找到 ‘运行’->点击->输入”cmd”->回车键   进入控制台命令窗口(如下图),先输入cd c:\   (作用是将命令路径改到c盘根目录),然后输入test.py运行我们刚刚写的程序:

得到的结果是C:\test.py,这就是0指代码(即此.py程序)本身的意思。其实应该只是test.py。

然后我们将代码中0改为1 :

a=sys.argv[1]

保存后,再从控制台窗口运行,这次我们加上一个参数,输入:test.py what

 得到的结果就是我们输入的参数what,看到这里你是不是开始明白了呢。

那我们再把代码修改一下:

a=sys.argv[2:]

保存后,再从控制台窗台运行程序,这次多加几个参数,以空格隔开:

test.py a b c d e f

得到的结果为[‘b’, ’c’, ’d’, ’e’, ’f’]


完整的例子

#!/usr/bin/env python  import sys   def main(argv):     print(argv[0])                 print(argv[1])     print(argv[1:])     print(argv[1][1:])       print('sys.argv[0]:',sys.argv[0])        #脚本名字      print('sys.argv[1]:',sys.argv[1])        #脚本第一个参数      print('sys.argv[1:]:',sys.argv[1:])        print('sys.argv:',sys.argv)            #脚本的所有参数    print('type(sys.argv):',type(sys.argv))    print('len(sys.argv):',len(sys.argv))       #脚本的参数个数       return 0    if __name__ == '__main__':      sys.exit(main(sys.argv[1:]))  #sys.exit(0)正常退出, sys.exit(1)非正常退出
#输入$ python ./test.py aa bb cc #输出aabb['bb', 'cc']bsys.argv[0]: test1.pysys.argv[1]: aasys.argv[1:]: ['aa', 'bb', 'cc']sys.argv: ['test1.py', 'aa', 'bb', 'cc']type(sys.argv): <class 'list'>len(sys.argv): 4

从上面输出结果可以看出,

sys.argv[0]是当前所执行的脚本,并且输入什么就是什么,输入test.py就是test.py,输入./test.py就是./test.py

index 1以后的才是所传入的参数。用sys.argv[1:]可以获取到所有的参数,并且输出到一个列表里面。


输入为 –numa=1  –numb=2 形式和  –numa 1  –numb  2 形式

 如果 python test.py –numa=1 –numb=2

则sys.argv[1:] 为 [test.py, –numa=1, –numb=2]

 如果 python test.py –numa 1 –numb 2

则sys.argv[1:] 为 [test.py, –numa, 1, –numb, 2]

#输入$ python test.py --numa=1 --numb=2 #输出--numa=1--numb=2['--numb=2']-numb=2sys.argv[0]: test1.pysys.argv[1]: --numa=1sys.argv[1:]: ['--numa=1', '--numb=2']sys.argv: ['test1.py', '--numa=1', '--numb=2']type(sys.argv): <class 'list'>len(sys.argv): 3 #输入$ python test.py --numa 1 --numb 2 #输出--numa1['1', '--numb', '2'] sys.argv[0]: test1.pysys.argv[1]: --numasys.argv[1:]: ['--numa', '1', '--numb', '2']sys.argv: ['test1.py', '--numa', '1', '--numb', '2']type(sys.argv): <class 'list'>len(sys.argv): 5

Python PyAudio实现自动回答问题仿Siri

Python 很强大其原因就是因为它庞大的三方库 , 资源是非常的丰富 , 当然也不会缺少关于音频的库

关于音频, PyAudio 这个库, 可以实现开启麦克风录音, 可以播放音频文件等等,此刻我们不去了解其他的功能,只了解一下它如何实现录音的

首先要先 pip 一个 PyAudio

pip install pyaudio

一.PyAudio 实现麦克风录音

然后建立一个py文件,复制如下代码

复制代码
import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 16000
RECORD_SECONDS = 2
WAVE_OUTPUT_FILENAME = "Oldboy.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

print("开始录音,请说话......")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("录音结束,请闭嘴!")

stream.stop_stream()
stream.close()
p.terminate()

wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
复制代码

尝试一下,在目录中出现了一个 Oldboy.wav 文件 , 听一听,还是很清晰的嘛

接下来,我们将这段录音代码,写在一个函数里面,如果要录音的话就调用

建立一个文件 pyrec.py 并将录音代码和函数写在内

复制代码
# pyrec.py 文件内容
import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 16000
RECORD_SECONDS = 2

def rec(file_name):
    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)

    print("开始录音,请说话......")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)

    print("录音结束,请闭嘴!")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(file_name, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()
复制代码

rec 函数就是我们调用的录音函数,并且给他一个文件名,他就会自动将声音写入到文件中了

二.实现音频格式自动转换 并 调用语音识别

录音的问题解决了,赶快和百度语音识别接在一起使用一下:

不管你的录音有多么多么清晰,你发现百度给你返回的永远是:

{'err_msg': 'speech quality error.', 'err_no': 3301, 'sn': '6397933501529645284'} # 音质不清晰

其实不是没听清,而是百度支持的音频格式PCM搞的鬼

所以,我们要将录制的wav音频文件转换为pcm文件

写一个文件 wav2pcm.py 这个文件里面的函数是专门为我们转换wav文件的

使用 os 模块中的 os.system()方法 这个方法是执行系统命令用的, 在windows系统中的命令就是 cmd 里面写的东西,dir , cd 这类的命令

复制代码
# wav2pcm.py 文件内容
import os

def wav_to_pcm(wav_file):
    # 假设 wav_file = "音频文件.wav"
    # wav_file.split(".") 得到["音频文件","wav"] 拿出第一个结果"音频文件"  与 ".pcm" 拼接 等到结果 "音频文件.pcm"
    pcm_file = "%s.pcm" %(wav_file.split(".")[0])

    # 就是此前我们在cmd窗口中输入命令,这里面就是在让Python帮我们在cmd中执行命令
    os.system("ffmpeg -y  -i %s  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s"%(wav_file,pcm_file))

    return pcm_file
复制代码

这样我们就有了把wav转为pcm的函数了 , 再重新构建一次咱们的代码

这次的返回结果还挺让人满意的嘛

{'corpus_no': '6569869134617218414', 'err_msg': 'success.', 'err_no': 0, 'result': ['老男孩教育'], 'sn': '8116162981529666859'}

拿到语音识别的字符串了,接下来用这段字符串 语音合成, 学习咱们说出来的话

三.语音合成 与 FFmpeg 播放mp3 文件

拿到字符串了,直接调用synthesis方法去合成吧

这段代码衔接上一段代码,成功获得了 synth.mp3 音频文件,并且确定了实在学习我们说的话

接下来就是让我们的程序自动将 synth.mp3 音频文件播放了 其实PyAudio 有播放的功能,但是操作有点复杂

所以我们还是选择用简单的方式解决复杂的问题,就是这么简单粗暴,是否还记得FFmpeg 呢?

FFmpeg 这个系统工具中,有一个 ffplay 的工具用来打开并播放音频文件的,使用方法大概是: ffplay 音频文件.mp3

建立一个playmp3.py文件, 写一个 play_mp3 的函数用来播放已经合成的语音

# playmp3.py 文件内容
import os

def play_mp3(file_name):
    os.system("ffplay  %s"%(file_name))

回到主文件,调用playmp3.py文件中的 play_mp3 函数

执行代码,当你看到 : 开始录音,请说话……

请大声的说出: 学IT 找老男孩教育

然后你就会听到,一个娇滴滴声音重复你说的话

四.简单问答

首先我们要把代码重新梳理一下:

把语音合成 语音识别部分的代码独立成函数放到baidu_ai.py文件中

复制代码
# baidu_ai.py 文件内容
from aip import AipSpeech

# 这里的三个参数,对应在百度语音创建的应用中的三个参数
APP_ID = "xxxxx"
API_KEY = "xxxxxxx"
SECRET_KEY = "xxxxxxxx"

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)


def audio_to_text(pcm_file):
    # 读取文件 , 终于得到了PCM文件
    with open(pcm_file, 'rb') as fp:
        file_context = fp.read()

    # 识别本地文件
    res = client.asr(file_context, 'pcm', 16000, {
        'dev_pid': 1536,
    })

    # 从字典里面获取"result"的value 列表中第1个元素,就是识别出来的字符串"老男孩教育"
    res_str = res.get("result")[0]

    return res_str


def text_to_audio(res_str):
    synth_file = "synth.mp3"
    synth_context = client.synthesis(res_str, "zh", 1, {
        "vol": 5,
        "spd": 4,
        "pit": 9,
        "per": 4
    })

    with open(synth_file, "wb") as f:
        f.write(synth_context)

    return synth_file
复制代码

然后把我们的主文件进行一下修改

复制代码
import pyrec  # 录音函数文件
import wav2pcm  # wav转换pcm 函数文件
import baidu_ai  # 语音合成函数,语音识别函数 文件
import playmp3  # 播放mp3 函数 文件

pyrec.rec("1.wav")  # 录音并生成wav文件,使用方式传入文件名

pcm_file = wav2pcm.wav_to_pcm("1.wav")  # 将wav文件 转换成pcm文件 返回 pcm的文件名

res_str = baidu_ai.audio_to_text(pcm_file) # 将转换后的pcm音频文件识别成 文字 res_str

synth_file = baidu_ai.text_to_audio(res_str) # 将res_str 字符串 合成语音 返回文件名 synth_file

playmp3.play_mp3(synth_file) # 播放 synth_file
复制代码

然后就是大展宏图的时候了,展开你们的想象力:

res_str 是字符串,如果字符串等于”你叫什么名字”的时候,我们就要给他一个回答:我的名字叫老男孩教育

新建一个FAQ.py的文件然后建立一个函数faq:

复制代码
# FAQ.py 文件内容
def faq(Q):
    if Q == "你叫什么名字": # 问题
        return "我的名字是老男孩教育" # 答案

  return "我不知道你在说什么" #问题没有答案时返
复制代码

在主文件中导入这个函数,并将语音识别后的字符串传入函数中

现在来尝试一下:”你叫什么名字”,”你今年几岁了”

成功了,现在你可以对 FAQ.py 这个文件进行更多的问题匹配了

还是那句话,别玩儿坏了

思考题:

1.如何实现一直问答不用问一次停一次?

2.问题那么多,是不是要写这么多问题呢?

3.如果我问你是谁,是不是要重复也一次 我的名字叫老男孩教育 的答案呢?分类: 跟DragonFire学Python人工智能应用好文要顶关注我收藏该文

DragonFire
关注 – 9
粉丝 – 637+加关注

几个好用的PHP IDE

NetBeans —— 免费,开源,跨平台,大公司支持

这是一款免费开源,跨平台的IDE,也是小编最喜欢的一款开发工具,他不用复杂的破解,注册,便可以下载使用(你知道,这有时候会让你没有罪恶感)。这个IDE是使用JAVA开发的重型IDE,所以有时候载入和使用时在差点的电脑上会有点慢。但是,现在的码农的电脑一般配置也不会太差。你不仅可以用它来编写PHP,也可以用来编写Java, JavaScript, HTML5, PHP, C/C++等等。更重要的是,他是ORACLE开发维护的,大公司有保证。同时,NetBeans还支持插件,这样可以很方便的对框架,cms一类的程序提供开箱即用的支持。当然它还拥有很多优秀的开发工具所共同拥有并必备的特性,拥有很多代码生成工具,像getter setter生成、代码模板、智能代码补全、提示、快速修复和重构等。另外还支持一些基本特性,包括代码折叠和格式化、try/catch代码补全以及矩形选区等。说着这么多,它排在第一名,是因为免费开源,并且是我最常用的IDE。

Zend Studio —— 收费,稳定,跨平台,大公司支持

这是一款Zend公司开发的,这个公司是不是很熟悉?对的,他就是常说的php公司,php的两位缔造者创建了这个公司。所以你就该放心了,毕竟它不仅是Zend公司的,还是收费的,这两个特性保证你用的爽。它提供了一些关键功能,其中包括在验证、索引和搜索PHP code方面性能更好。使用Zend Debugger、Xdebug和内置的Z-Ray工具进行调试。支持Eclipse插件生态系统。支持Docker和Git工具。支持PHP、Javascript,、CSS和HTML的智能代码编辑。部署支持,包括提供了对Microsoft Azure和Amazon AWS的云支持。集成了Zend server,有助于PHP7的快速迁移和无缝连接。还有一个功能,可能会对你很有用,它可以开发移动应用程序哟。

Sublime Text —— 免费,收费,轻型,跨平台,漂亮

它可能是我见过最漂亮的文本编辑器了。当然了,对于码农来说,漂亮这个词用途并不大。相对于上面两个重型开发工具IDE来说,它可能算的上是小巧玲珑了。但是它也可以通过插件和包来变得更加强大。起初他就像一个不施粉黛的小家碧玉,但是通过不断地定制化,它肯定不会输给其他IDE的。这里推荐几个有用并常用的包,package control,Sublime PHP companion, xDebug client——CodeBug, PHPCS, CodIntel, Simple PHPUnit 和 PHPDoc。还是那句话,第一眼,你便会看上它,毕竟它很漂亮。

Vim —— 免费,开源,轻型,跨平台

熟悉Linux的同学,肯定没少用Vim,为什么我们推荐这个“简陋的”编辑器呢?其实Sublime Text的理念跟Vim的差不多,都可以通过定制化,让它更独特,更加的适合自己,虽然这样会增加复杂性,会增加你一开始的工作量。但是它是一个与时俱进的IDE,至今还有不少人活跃在社区上,为它更新,为它讨论,通过不同的配置,会让你开发越加顺手。还有一个重要的优点,它更加符合Linux的风格,不用或少用鼠标就可以完成全部工作。Windows环境中开发工作中,大家在写代码的时候,免不了要使用到鼠标,点点这点点那,降低工作效率。在Windows下,你同样可以使用gvim。它是Vim的图形前端,跨平台。

今天就为大家推荐这几个我最常用的IDE/开发工具。虽然少,但是个个招式高超,精通一样便可以称霸武林,笑傲江湖。最后送给大家一句话:理想如果不向现实做一点点屈服,那么理想也将归于尘土。

Vultr高频运算服务器测评

转自曙光博客

Vultr刚刚推出了新产品线:High Frequency Compute(下面简称HFC主机),该系列的主机,采用了3Ghz+的CPU和Nvme的SSD,Vultr说这是他们到目前为止,推出的性能最好的主机。据介绍,在CPU和IO上,HFC主机比ECS(就是普通的SSD VPS)要快40%。

HFC主机目前只在New Jersey机房有售,将在未来几个月部署到全球其他机房。最低的配置为1核心CPU,1G内存和32G的Nvme SSD,价格为6美元每个月。

价格提升了20%,但是性能却提升了40%,也算间接地降价吧。

下图是性能测试,根据以前的IO算,IO是以前的两倍以上;以前主机的CPU主频为2.4Ghz,新款的为3.8Ghz,当然CPU的性能不能简单地从主频来判断。

vultr-hfc-bench.png

官方页面介绍最低配的HFC款,Geekbench 4.3.3测试的单核成绩为6375,多核成绩为6017,经过我的实测,单核为5225,多核为4973,有一定的差距。开了几台机器测试,单核最多在5300多点。

重要的介绍完了,顺便说下:

1,他们取消了Storage系列的主机,这个系列的主机在很久之前就处于缺货状态了。

2,他们设计了新的Logo和网站。

vultr-new-logo.png

云计算,雾计算,边缘计算的联系及区别

自从“云计算”与其分支“边缘计算”和“雾计算”推出以来,这三者之间的差异甚至让许多专业人士都感到困惑。但是当涉及到一般消费者、IT 开发人员、数据分析师和企业网络时,选择一个或多个这样的计算平台可以获得明显的优势。这些计算将为不同的环境和场合提供不同的功能,即使它们彼此相辅相成。

以下是对这三个层次的计算类別的概述,以及每个计算层次的实际应用情况。如上所述,术语“云”“边缘”和“雾”代表三层计算:

▲ 云计算层:工业大数据、业务逻辑和分析数据库以及数据存储。

▲ 雾计算层:本地网络资产、微型数据中心。

▲ 边缘计算层:工业 PC、特定于流程的应用以及自治设备上的实时数据处理。

将它们视为层,在视觉上是有帮助的,因为每一层都建立在前一层的基础功能之上,并且每一层都提供更接近数据源的智能分析。那么来源来自哪里?在制造业中,它可能是一个带有网络连接的生产设备的车间和工厂。在 IT 环境中,可操作数据的来源可能包括企业路由器和员工终端。

雾计算的实际应用

那么什么是雾计算呢?雾计算可以有效地分散计算和分析能力。它位于本地设备和移动设备之间,换句话说,它们是具有有限的处理能力和存储设备,并提供了一种筛选来自物联网组件信息流的方法。

无人驾驶汽车在城市街区的导航,可以让人们得到雾计算的最初印象。如果车辆、传感器和控制器是城市智能交通系统的“边缘层”,这意味着就要进行边缘计算——那么就需要构建和运营微型数据中心,那么很可能采用微型数据中心和网状路由器以及服务器作为“雾计算层”。雾计算并不像边缘计算那样分散,但它确实进一步减少了通过网络或向上传输到云计算层的数据量。它有助于边缘层中“节点”之间的通信和协作。在上面的示例中,节点是无人驾驶汽车。

那么,有哪些工业用途的应用呢?与业务相关的一个例子是自动库存系统,它位于供应链中的多个仓库和工厂之间。在这里,雾计算层可以用于“检查和平衡”多个位置的材料、设备和供应水平,并自动触发重新订单。

雾计算代表了一个重要的中间步骤,它控制着运营数据通过组织的设备和局域网以及决策者(或最终是工业级云数 据服务)的移动量和类型。通过这种方式,雾计算可以帮助减少带宽使用,甚至减缓企业进行昂贵升级的需求,以及帮助企业保持 IT 基础设施平稳运行。“智能计量”是应用于电网的一个例子。“智能计量”是指本地数据中心与发电厂和变压器一起部署,以收集和传输有关当地电网的信息。通过雾计算以这种方式控制的“智能电网”在限制停电影响方面更具弹性,并使工程师在问题突现时更容易查明。

边缘计算的实际应用

随着从云计算层发展到雾计算,并最终到边缘计算的每一步,“智能设备”是一种更接近数据源进行信息处理的设备。因此,通过边缘计算,可以在局域网上的单个机器、工作站和移动设备上进行智能分析。它就像工厂中的自动化控制器;智能设备操作机器,标记维护项目,以及向云计算和企业决策者“向上”分流传人数据。工业数据科学家收到来自雾计算层或云计算即服务层的数据,可以深入了解当前运营状态,并有助于产生更好的预测。

以下是有关如何利用边缘计算的三个示例:

1.测试大型设备需要灵活的数据流,通常详细说明许多关键部件的性能。设备测试设施中的“边缘层”可能包括无线温度计、振动传感器和其他仪表。

2.依据前文可以推断,智能的交通管理将很快成为常态。有关交通模式的分析和情报将在本地、自动驾驶车辆以及交叉路口和交通管理协议中使用固定传感器进行。在这种情况下,边缘计算看起来像一种“连接网络”,它允许每个相关设备通过有意义的、可操作的实时数据来支持其他设备。

3.更加智能的工厂是工业用边缘计算最明显的应用之一。通过将边缘节点与雾计算相结合,工厂内的许多系统可以实现自动化,其中包括生产设备、环境控制、压缩空气系统、 冷却剂循环、电力和其他电源等。

雾计算和边缘计算为消费者、企业、数据科学家和 IT 架构师创造了大量全新的工具,以实现卓越的效果。人们可能已经注意到在某种程度上略胜于一般的云计算。让我们重新回到计算层次的顶层,简要回顾一下云计算的最新发展,以及它帮助创建的机会和新的专业。

云计算是什么

当人们谈论云计算时,往往带着一种神秘感或混乱感,但它真正指的是现在的互联网连接。考虑一下之前经历过的事 物。工厂、商业场所或消费者设备曾经是一个完全孤立的孤岛。它可能包含有用的数据,但是在云连接变得更容易访问之前,从这些孤立的系统中提取数据是一项艰巨的任务。如今的创业公司层出不穷,互联网无处不在,连接触手可及,年轻一代可能对云计算的早期发展没有太多的印象。然 而,在短短几年内,在工业和商业方面,访问基于云计算的连接工具彻底改变了游戏规则。

现在,即使是预算有限的企业也可以访问服务器和进行基于云计算的分析,这些分析可以集中计算能力,并使其业务的许多部分保持联系。有些人甚至声称云计算已经在商业中占据了一席之地,创业公司可以在没有大量资金的情况下更快速、更无缝地扩展,并且更有效地竞争,提供更多时间扩展以及实现基础设施多样化。

满足各种需求的计算层

IT 基础设施技术的多样化导致了云计算层得到广泛应用。其结果是为各行业专业人士和企业带来了新的机遇,更不用说为数据科学家、IT 专家和分析专家等提供广泛的学科选择和工作保障。企业运营业务是自己构建(或租赁)通用云计算基础设施,还是选择使用雾计算和边缘计算等更专业的工具?这取决于企业的需求和发展,而企业采用这些计算工具可以获得竞争优势。

作者:林小新,文章首发于《计算机与网络》。

了解更多边缘计算资讯,尽在边缘计算社区,百度搜索:边缘计算社区