opencv教程CV2模块——图片处理,裁剪缩放加边框
import cv2 # 读取图片 img = cv2.imread('./imgg/1.jpeg') # 缩放成200x200的方形图像 img_200x200 = cv2.resize(img, (200, 200)) # 不直接指定缩放后大小,通过fx和fy指定缩放比例,0.5则长宽都为原来一半 # 等效于img_200x300 = cv2.resize(img, (300, 200)),注意指定大小的格式是(宽度,高度) # 插值方法默认是cv2.INTER_LINEAR,这里指定为最近邻插值 img_200x300 = cv2.resize(img, (0, 0), fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST) # 在上张图片的基础上,上下各贴50像素的黑边,生成300x300的图像 img_300x300 = cv2.copyMakeBorder(img, 50, 50, 0, 0, cv2.BORDER_CONSTANT, value=(0, 0, 0)) # 对照片中树的部分进行剪裁 patch_tree = img[20:150, -180:-50] cv2.imwrite('./out/cropped_tree.jpg', patch_tree) cv2.imwrite('./out/resized_200x200.jpg', img_200x200) cv2.imwrite('./out/resized_200x300.jpg', img_200x300) cv2.imwrite('./out/bordered_300x300.jpg', img_300x300)
一、数据库 https://www.cnblogs.com/wenxiaofei/p/9853682.html
Q:数据库中的事务了解吗?事务的四大特性?
数据库事务是数据库运行中的逻辑工作单位,单个逻辑工作单元所执行的一系列操作,要么都执行,要么都不执行。例如银行取款事务分为2个步骤(1)存折减款(2)提取现金,2个步骤必须同时完成或者都不完成。
数据库事务的四大特性(ACID):
(1) 原子性(Atomicity):
事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行。这种特性称为原子性。
(2)一致性(Consistency) :
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。
(3)分离性(Isolation):
分离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。假如并发交叉执行的事务没有任何控制,操纵相同的共享对象的多个并发事务的执行可能引起异常情况。
(4)持久性(Durability):
持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。即一旦一个事务提交,DBMS保证它对数据库中数据的改变应该是永久性的,即对已提交事务的更新能恢复。持久性通过数据库备份和恢复来保证。
Q:如何理解数据库的范式?
第一范式(1NF):确保每一列的原子性;如果每一列都是不可再分的最小数据单元,则满足第一范式。
第二范式:非键字段必须依赖于键字段;如果一个关系满足1NF,并且除了主键以外的其它列,都依赖与该主键,则满足二范式(2NF),第二范式要求每个表只描述一件事。
第三范式:在2NF的基础上,不存在传递依赖
Q:什么叫视图?游标是什么?
视图:是一种虚拟的表,具有和物理表相同的功能,它可以对试图进行增删改查操作,试图通常是一个表或者多个表的行或者列的子集,对视图的修改会不影响基本表。它使得我们获取数据更容易,相比多表查询。
游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
Q:视图的优缺点
优点:
①简化了操作,把经常使用的数据定义为视图。
②安全性,视图随着基表的变化而更新,但不会通过视图修改基本表的数据,保证了数据的安全性
③可以合并分离的数据,创建分区视图,更好的实现数据的对比
缺点:
①性能:SQL Server必须把视图的查询转化成对基本表的查询,如果这7a64e78988e69d8331333236373831个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,SQL Server也把它变成一个复杂的结合体,需要花费一定的时间。
②修改限制:当用户试图修改视图的某些行时,SQL Server必须把它转化为对基本表的某些行的修改。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的。
Q:数据库为什么需要锁机制?有哪些锁机制?
https://www.cnblogs.com/xiaofengwang/p/11291944.html
保证数据库事务的一致性;防止出现(数据库的隔离级别:脏读,不可重复读,幻读等并发事件https://www.jianshu.com/p/d9389f27ca1a)
锁分为行级锁、表级锁、悲观锁、乐观锁
Q:drop、truncate、 delete区别
drop直接删掉表。truncate删除表中数据,再插入时自增长id又从1开始。delete删除表中数据,可以加where字句。 Q:理解数据库的触发器
Q:重要的SQL语句举例
二、离散数学 Q:
三、计算机网络 Q:谈谈对TCP/IP协议的理解
Q:TCP的三次握手和四次挥手
Q:TCP和UDP的区别
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
Q:拥塞控制和流量控制都是什么,两者的区别?
流量控制是端到端的控制,例如A通过网络给B发数据,A发送的太快导致B没法接收(B缓冲窗口过小或者处理过慢),这时候的控制就是流量控制,原理是通过滑动窗口的大小改变来实现。 拥塞控制是A与B之间的网络发生堵塞导致传输过慢或者丢包,来不及传输。防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不至于过载。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络性能有关的所有因素。
Q:访问一个网页的过程
https://blog.csdn.net/huangwei18351/article/details/81456228
1、解析baidu.com域名对应的ip地址
1.1使用ARP(Address Resolution Protocol)地址解析协议获得默认网关的MAC地址;
1.2组织数据发送给默认网关(ip还是DNS服务器的ip,但是MAC地址变成了默认网关的MAC地址);
1.3默认网关具有转发数据的能力,他把数据转发给路由器;
1.4路由器根据自己的路由协议,选择一个合适的较快的路径转发数据给目的网关(DNS服务器所在的网关);
1.5目的网关把数据转发给 DNS服务器;
1.6DNS服务器查询解析出baidu.com对应的IP地址,并将此IP地址俺原路返回给请求这个域名IP的客户端。
给你一个非递减的 有序 整数数组,已知这个数组中恰好有一个整数,它的出现次数超过数组元素总数的 25%。
请你找到并返回这个整数.
示例: 输入:arr = [1,2,2,6,6,6,6,7,10] 输出:6 提示: 1 <= arr.length <= 10^4 0 <= arr[i] <= 10^5 解题思路:
首先求出数组长度的25%,然后再通过比较 nums[i] == nums[i+length],如果是true,那么就直接返回nums[i];
public static int findArr(int [] nums){ int length = nums.length / 4; for (int i = 0; i < nums.length - length; i++) { if (nums[i] == nums[i + length]){ return nums[i]; } } return nums[0]; }
SpringBoot整合Shiro后实现免密登录
1,说明一下步骤,需要在原来基础新增三个文件
2,新增CustomToken,重写UsernamePasswordToken免密登录调用方法和密码登录调用方法都在里面。
3,新增MyRetryLimitCredentialsMatcher,重写HashedCredentialsMatcher,主要是判定登录是否是免密登录。
4,新增LoginType,登录类型枚举
5,修改ShiroConfig文件,即Shiro配置文件,主要关注:57,63,65-90行
CustomToken.java package com.fc.test.shiro.nopassword; import org.apache.shiro.authc.UsernamePasswordToken; /** * 重写UsernamePasswordToken * @ClassName: UsernamePasswordToken * @author zlxls * @date 2020年04月11日 */ public class CustomToken extends UsernamePasswordToken { private static final long serialVersionUID = -2564928913725078138L; private LoginType type; public CustomToken() { super(); } public CustomToken(String username, String password, LoginType type, boolean rememberMe, String host) { super(username, password, rememberMe, host); this.type = type; } public LoginType getType() { return type; } public void setType(LoginType type) { this.
文章目录 一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码 一、为啥要使用第三方Log库,而不用平台自带的Log库 首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但是在深入使用的场合则显得“心有余而力不足”了。
比如在如下几个使用场合:
记录软件崩溃log文件:
正式发布的软件,需要把使用过程中的报错信息写入到log文件中。这个“Log文件”主要记录软件的使用环境、操作动作、警告信息、报错信息等。在软件发生崩溃的时候,这些log文件对开发者定位bug并修改bug有非常大的帮助。是大型软件必不可少的功能。记录软件使用详细过程
对于一些涉及数据安全的软件,需要对软件的操作步骤和过程做详细的log记录。从而避免操作人员随意或恶意修改数据却不留下任何证据。比如:医疗数据、金融数据、电力数据、化工数据等。同时为了log记录的安全,需要远程储存log数据。常用的方式是用“远程数据库”来记录log。
因此,在这些重量级的需求下,发展出来了各种个样的第三方Log库,而最为著名的就是Log4J这个开源库。 二、Log4j系列库的功能介绍与基本概念 Log4J相比于系统自带log的优点 支持多源输出:支持输出log到控制台、文件、套接口服务器等;线程安全:可以安全的在多线程应用中使用;输出格式可控:可以根据需求定制输出格式:xml格式、数据库表格式、(时间,日期,线程,级别)自由组合格式;支持日志级别:可以用不同级别来记录log,比如:debug、info、warn、error。同时可以灵活限定输出等级;配置简单:使用统一的配置文件配置即可实现定制化的log输出,配置文件可以随时修改动态生效;多个输出源同时输出:比如终点输出和文件输出可以同时记录log;多平台可用:现在Log4J被移植到多个平台上支持多种编程语言; Log4j的组成部分
Log4j由三个组件组成,分别是:记录器(logger)、数据输出源(appender)、布局(layout)。开发者可以根具输出消息类型、等级、输出格式以及使用那种方式输出作出灵活的配置。这些都离不开这三个组件的支持。 记录器(logger):在代码中采集需要输出的消息。并且根具所配置的等级过滤输入消息数据输出源(appender):log消息数据输出的目标地点。比如:终端、文件、远程socket布局(layout):指定消息输出的格式。比如:xml格式、时间,日期,线程,级别)自由组合格式; Log4j的输出等级
日志信息的优先级从高到低有FATAL、ERROR、WARN、INFO、DEBUG、TRACE、ALL,分别用来指定这条日志信息的重要程度。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。Log4j只输出,级别设置等级以及比设置等级高的消息。比如设置等级为Info。则属于“FATAL、ERROR、WARN、INFO”等级的消息可以输出到log。而“DEBUG、TRACE”级别的消息则不会被输出。
常用的输出源(Appender)
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
常用的布局(Layout)
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(根据patten符号格式化输出数据,类似printf的格式化方式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
一些规则说明
一个Logger可以挂接多个Appender(日志信息同时转发到多个输出源)一个Appender只能指定一个Layout进行格式化RootLogger可以设置一个基本log输出等级限制每个Appender可以单独设置自己的输出等级,但是受限于RootLogger的log输出等级限制 三、Log4Qt库的基本介绍 Log4Qt作为Log4j的一个分支扩展。使得在Qt应用程序中也可以使用到这个优秀的log库。在Apache-2.0协议下发布,这个开源库可以使用在开源软件和商业软件中。项目地址如下:
https://github.com/MEONMedical/Log4Qt Log4qt在Log4j的基础增加的功能
//简单的包含时间“输出布局”
SimpleTimeLayout (“dd.MM.yyyy hh:mm [Thread] Level Logger Message”)
//多彩颜色终端输出(仅支持windows)
ColorConsoleAppender (render colorized message by escape sequence and put it to console)
//当记录输出消息的时候,发生一个qt平台的信号
SignalAppender (emit signal when log event happens)
//数据库“输出源”
DatabaseAppender (append log event into sql table)
今天在进行一对多的left join处理的时候发现分页的数据量不正确,后来把打印的sql去数据库执行,查询出来的确实是10条,只不过是1:N的数据是10条。这并不是想要的,应该查到主表的数据是10条。
在xml里进行更改collection的映射
<resultMap id="recordEventMap" type="MaterialRecordEventEntity"> <id column="id" property="id"></id> <result column="user_id" property="userId"></result> <result column="type_id" property="typeId"></result> <result column="create_time" property="createTime"></result> <collection property="children" column="id" select="queryRecordItem"></collection> </resultMap> <select id="pageInfo" resultMap="recordEventMap"> SELECT re.id, re.user_id, re.type_id, re.create_time FROM record_event re ORDER BY re.id DESC </select> <select id="queryRecordItem" resultType="RecordEntity"> SELECT mr.sum, material_id, mr.project_id, mr.bom_id, mr.storage_id, mr.company, mr.remark FROM nzic_material_record mr WHERE mr.tra_no = #{id} </select> 主要就是把collection的映射数据拿一个子查询去映射,column就是从表要关联主表的那个字段,这样查询出来的数据就是正常的了。
CMake Error at /usr/src/gmock/CMakeLists.txt:51 (add_subdirectory):
add_subdirectory given source “…/gtest” which is not an existing
directory.
CMake Error at /usr/src/gmock/CMakeLists.txt:56 (config_compiler_and_linker):
Unknown CMake command “config_compiler_and_linker”.
应该还是库的问题,下载Googletest之后编译安装,将文件夹烤入报错的目录下.
导读:在讲《Apache Druid 底层存储设计》时就说过要讲一讲列式存储。现在来了,通过本文你可以了解到行存储模式、列存储模式、它们的优缺点以及列存储模式的优化等知识。
今日格言:不要局限于单向思维,多对比了解更多不同维度的东西。
从数据存储讲起 我们最先接触的数据库系统,大部分都是行存储系统。大学的时候学数据库,老师让我们将数据库想象成一张表格,每条数据记录就是一行数据,每行数据包含若干列。所以我们对大部分数据存储的思维也就是一个复杂一点的表格管理系统。我们在一行一行地写入数据,然后按查询条件查询过滤出我们想要的行记录。
大部分传统的关系型数据库,都是面向行来组织数据的。如 Mysql,Postgresql。近几年,也越来越多传统数据库加入了列存储的能力。虽然列存储的技术在十几年前就已经出现,却从来没有像现在这样成为一种流行的存储组织方式。
行存储和列存储,是数据库底层组织数据的方式。(和文档型、K-V 型,时序型等概念不在一个层次)
行存储 行存储系统以行的方式来组织数据。假设现在有以下 blog 数据(大学时老师布置系统课题作业总是让我们做一个博客系统,大概因为他们最先接触的互联网就是 BBS 吧):
[ { "title": "Oriented Column Store", "author": "Alex", "publish_time": 1508423456, "like_num": 1024 },{ "title": "Apache Druid", "author": "Bob", "publish_time": 1504423069, "like_num": 10 },{ "title": "Algorithm", "author": "Casey", "publish_time": 1512523069, "like_num": 16 } ] 行存储将会以下列方式将数据存储在磁盘上。我们可以思考一下,这样的方式利于什么样的存储?(此处停顿 5 秒思考一下)它利于数据一行一行的写入,写入一条数据记录时,只需要将数据追加到已有数据记录后面即可。
行模式存储适合 OLTP(Online Transaction Processing)系统。因为数据基于行存储,所以数据的写入会更快。对按记录查询数据也更简单。
大部分同学会问,我们的做的系统不就是在为了这个吗?所以我为什么还需要列式存储,而列式存储又是什么?
让我们想象一种场景,现在不是想查询 Bob 的博客,我想统计 Bob 发表的博客数,或是整个系统今天的博客点赞数。如果是行存储系统,数据库将怎样操作?(停顿思考 10 秒)
如图,想统计所有点赞数,首先需要将所有行数据读入内存,然后对 like_num 列做 sum 操作,从而得到结果。我们假设磁盘一次可以读取图中 3 个方框的数据(实际需要按 byte 来读取),那么这个聚合计算需要 N(N=数据量)次磁盘访问。
RTC(Real Time Clock)是实时时钟的意思,它其实和TIM有点类似,也是利用计数的原理,选择RTC时钟源,再进行分频,到达计数的目的。
RTC的秒中断功能类似SysTick系统滴答的功能。RTC秒中断功能其实是每计数一次就中断一次。注意,秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。
例:
主函数间隔0.5秒LED变化一次;
秒中断一次打印数据"RTC Sec...";
也就是LED变化一次,串口打印一次数据"RTC Sec..."
扩展部分的功能RTC计数:可以实现RTC闹钟
原理描述
从框图中大概就可以看到该模块有些什么功能及其工作的原理。
RTC框图:
从上面系统框图来分析“RTC秒中断”的原理:
1、RTC时钟源,总共有三类:可任意选择,并配置成任意秒数为周期
RCC_RTCCLKSource_LSE
RCC_RTCCLKSource_LSI
RCC_RTCCLKSource_HSE_Div128
本文实例代码是:RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
使用“RCC_RTCCLKSource_HSE_Div128”作为时钟源(高速时钟源),也就是外部高速时钟的128分频,也就是每秒8M/128(62500)个脉冲;
当然,我们也可以选择另外两个时钟源,也就是使用低速时钟源,一般应用在RTC闹钟可RTC日历等都使用低速时钟源。
2、RTC分频:
本文实例代码是:RTC_SetPrescaler(62500);
这个值是和上面对应的,因为我们这里是实现真正的1秒钟中断一次。
3、RTC中断:
RTC中断有三种:
RTC_IT_SEC秒中断(一个周期中断一次,自己进行配置)
RTC_IT_ALR闹钟中断
RTC_IT_OW(计数)溢出中断
本文实例是:RTC_ITConfig(RTC_IT_SEC, ENABLE);
使能RTC_IT_SEC秒中断。
再次强调:
这里的“秒中断”是概念上的秒中断,它的中断间隔时间是根据你选择的时钟源和分频值决定的,并非真正的1秒钟中断一次。
我们可以试着将源代码中的分频值该62500的一半31250,可以看得出来,秒中断的间隔时间为0.5秒(请自行修改实验测试)。
下面将讲述关于“RTC秒中断”重要的、容易弄错的几点:
1.RCC时钟源
该函数位于bsp.c文件下面;
RCC是很多初学者,甚至已经工作的朋友容易遗漏的地方,有很多朋友觉得它使用的外设不正常,很大部分是没有配置RCC导致的。
重点注意:
A.外设RCC时钟的配置要在其外设初始化的前面;
B.匹配对应时钟。
比如:RCC_APB2外设不要配置在RCC_APB1时钟里面
2. RTC秒中断配置
该函数位于rtc.c文件下面;
该函数请结合参考手册(框图和寄存器)理解。
注意4点:
A.使能后备区域:PWR_BackupAccessCmd(ENABLE);
从系统框图可以看见RTC有阴影部分,其实这部分就是后备区域。因此,需要使能,这也是为什么上面需要配置RCC时钟的原因。
B.选择RTC时钟源:RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
在原理描述中说了,RTC时钟源有三种:任意选择
RCC_RTCCLKSource_LSE
RCC_RTCCLKSource_LSI
RCC_RTCCLKSource_HSE_Div128
C.使能RTC秒中断:RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC有三类中断:
RTC_IT_SEC秒中断
RTC_IT_ALR闹钟中断
RTC_IT_OW(计数)溢出中断
D.RTC分频:RTC_SetPrescaler(62500);
我们是为了得到真正的1秒钟中断一次,所以这里的值是62500 = 8M/128,这样才能刚好1秒中断一次。
3. NVIC配置
该函数位于bsp.c文件下面;
我们要中断,就需要配置NVIC(中断控制器),为其分配优先级。
题目描述 求字典序在s1和s2之间的,长度在len1到len2之间的字符串个数,结果 mod 1000007.
输入描述 每组数据包涵s1(长度小于100),s2(长度小于100),len1(小于100000),len2(大于len1,小于100000)
解题思路 算出两个字符串各自每位s[i]-'a’的值,得出总的字典序和Count,然后Count(s2)-Count(s1)-1
#include <iostream> using namespace std; int Count(string s) { int ret = 0; for(int i = 0; i < s.size(); i++) { //排列组合,每位都有26种搭配,所以每次都要乘26 ret = ret * 26 + s[i] - 'a'; } return ret; } int main() { string s1, s2; int len1, len2; while(cin >> s1 >> s2 >> len1 >>len2) { cout << (Count(s2) - Count(s1) - 1) % 1000007 << endl; } return 0; }
若要安装并开始使用 WSL 2,请完成以下步骤:
WSL 2 仅适用于 Windows 10 版本 18917 或更高版本
请确保你已安装 WSL(可以在此处找到有关执行此操作的说明),并且运行的是 Windows 10 版本 18917 或更高版本 若要确保使用的是版本 18917 或更高版本,请加入 Windows 预览体验计划并选择“快速”环或“慢速”环形。可以通过打开命令提示符并运行 ver 命令来检查 Windows 版本。 启用“虚拟机平台”可选组件使用命令行设置要由 WSL 2 支持的发行版验证发行版使用的 WSL 版本 启用“虚拟机平台”可选组件并确保启用了 WSL 文档已迁移
前言 游戏开发圈里的人一定听过优化游戏要降低DrawCall,这样到底什么是DrawCall呢?Unity中应该如何降低DrawCall,这里就来讲解一下关于DrawCall知识点。
1.是谁拖了后腿? 通俗的来说就是Cpu:(#`O′)喂你好,是Gpu吗?快点醒醒我这里又有画画的任务了(Cpu调用Gpu的次数),打一个比方比如上传很多文件到百度云或其他地方时,都会把它压缩到一个文件夹里,不会把它们分开上传(当然还有原因就是它们数据是相关,比如是主题的一套ico文件或软件的安装文件),排除这些和文件整合的原因,假设网速没有波动,分开传和压缩包,压缩包速度一定快很多的(不仅仅是因为压缩包更小),主要是每次上传还有一些预备动作(比如与服务器链接,初始化Socket等等),细心的会发现文件当拖动到百度云会有几毫秒的延迟。其实优化DrawCall主要是Cpu的处理速度的优化,Cpu和Gpu是并行工作的,处理的方式有一个命令缓存区,具体如图所示:
别看图中画的好像是Cpu在等待Gpu,实际上Cpu才是拖后腿的那个,现实中Gpu早就把命令缓存区里命令都处理完毕了,Cpu确还在准备DrawCall的命令,Cpu通过图像编程接口向命令缓存区添加命令,而Gpu通过缓存区获取命令处理。
2.为什么会拖后腿? 在每次调用DrawCall之前,因为Cpu需要向Gpu发送很多内容,包括数据、状态和命令,在这个阶段Cpu需要完成很多工作,比如检查渲染状态等(有一堆工作要Cpu处理,才会存放到缓存区),存放到缓存区以后,Gpu就要开始工作了,Gpu渲染能力还是很强的,渲染200或2000个三角网格通常看不出区别,导致Gpu渲染速度大于Cpu的提交速度,影响渲染流水线速度就是提交比较慢的Cpu(现在知道玩游戏要买的电脑配置了吧,一般选择Cpu比较好的,Gpu一般的即可,当然游戏画面特别好的,还是建议把显卡买好点的,有些游戏硬性条件普通显卡根本渲染不了,并不是渲染速度的问题了),最后可想而知Cpu会花费大量的时间在提交DrawCall的路上,造成Cpu的过载,Gpu确会出现空闲。
3.优化DrawCall 降低DrawCall的方式还是很多的,先讨论如何降低2d游戏的DrawCall,2d游戏的资源都是图片,单个图片调用一次DrawCall会导致Cpu太难了,这样有没有办法降低提交次数呢?可以通过打包图集的操作来降低DrawCall,比如界面所用到的图片打包成图集或者人物的序列图打包到图集,具体如图所示:
可能会思考把所有界面的资源打包到一个图集里,岂不是美哉?这个时候Gpu会说太难了,只是渲染某个界面却要拿出整个图集去操作,热更新也会说我太难了,只是更新某个界面里的按钮图片样式却要替换整个图集,所以合理打包图集。
其实对图集这个东西理解还是比较深刻,写过和看过图集打包软件的源代码(当然和Unity的图集不是一个,但是大同小异),一般情况就是把图片数据全部写到一个文件里,然后保存ID或其他信息可以把单个图片找出来的方式,通过图集实现了提交大量的DrawCall。接下来思考模型如何降低DrawCall的调用。 Unity中可以通过静态批处理实现优化DrawCall,静态批处理的原理就是合并网格,而合并过程是需要消耗时间,因此批处理技术更加适合那些静态的物体,比如不会动的地面、树和石头,对于这些静态物体我们合并一次即可,当然可以使用动态批处理,但是,由于这些物体不断移动的,因此每帧都需要进行合并发送给Gpu,对时间和空间都有一定的影响。具体如图所示:
我们不少网友和我一样,XShell 和 XFtp 是一般必备的建站和服务器运维工具。虽然官方有提供免费个人版本,但是还是有不少限制的,比如在同时开启管理服务器站点标签数的时候只能同时开启两个。这次疫情期间,看到 netsarang 有发布免费领取 Xmanager/Xshell/Xftp 授权码活动。虽然有效期也不过半年左右时间,但是好歹也是有免费的,如果有需要体验下原本商业才可以使用的功能,可以申请领取。
领取地址:https://www.netsarang.com/en/free-wfh-license-covid19/
目前有效期截止到6月30日,到时候会根据情况可能会延长。这个稍微做的有点吝啬了,免费一年又怎么了嘛。
css中强制不换行,文本不会换行,文本会在在同一行上继续,直到遇到<br>标签为止。
white-space:nowrap;
css中强制不换行,文本不会换行,文本会在在同一行上继续,直到遇到<br>标签为止。
话不多说,直接上代码
BresenhamLine.m
function BresenhamLine(x0,y0,x1,y1) dx=x1-x0; dy=x1-x0; len=max(abs(x1-x0),abs(y1-y0)); d(1)=dx-2*dy; up=2*dx-2*dy; down=-2*dy; x(1)=x0; y(1)=y0; for n=1:len x(n+1)=x(n)+1; if d(n) < 0 y(n+1)=y(n)+1; d(n+1)=d(n)+up; else y(n+1)=y(n); d(n+1)=d(n)+down; end end for n=1:len plot(x,y); end BrsenhamLineGUI.m
clc; clear; close all; ha = axes('Units', 'pixels', 'Position', [40, 40, 400, 400]); ptgrid = uicontrol('Style', 'pushbutton', ... 'String', '网格', 'Position', [450, 150, 60, 30], 'Callback', 'grid'); btncla = uicontrol('Style', 'pushbutton', ... 'String', '清除', 'Position', [450, 100, 60, 30], 'Callback', 'cla'); btnplot = uicontrol('Style', 'pushbutton', .
一群热爱技术并且向往优秀的程序猿同学,不喜欢水文,不喜欢贩卖焦虑,只喜欢谈技术,分享的都是技术干货。Talk is cheap. Show me the code 通过码云来导入github,通过码云下载
第一步:
找一个你需要下载的GitHub项目
第二步:
复制链接
第三步:
打开码云,然后选择从GitHub导入
第四步:
复制刚才的连接,起个名字,点击导入
这个过程大概一两分钟
导入完成:直接下载zip
一个完整的过程动图
PS: 如需更改git中的项目,打开你的项目,找到隐藏的文件夹git,记事本打开config,然后把remote"origin"中的url的gitee改成github 本来小编只是知道,怎么下载,不知道怎么更改github的项目,看到评论区提供的,今天早上去b站我才知道原来这个有b站up主发过了,而且更全面,这里附上地址
基础理论的缺失是人工智能进一步发展的瓶颈之一,国内外很多学者正在从各个学科的角度,为揭开AI算法黑匣子探索新的突破口。而本文介绍的嘉宾,智源学者史作强近年来则独辟蹊径地将常用于物理学研究的数学工具——微分流形和偏微分方程应用于机器学习、深度学习的研究,并承担了智源研究院课题项目《数据中的流形建模、理论及算法》。
史作强,清华大学数学科学系副教授,博士毕业于清华大学周培源应用数学研究中心,后赴美国加州理工学院应用与计算数学系做博士后,并曾作为访问学者在美国加州大学洛杉矶分校数学系访问一年。史作强一直在偏微分方程的数值方法等领域耕耘不辍、成果颇丰,那么他眼中用数学理解新事物的妙用有哪些?流形、偏微分方程和人工智能具体有哪些关联?能解决哪些具体问题?同时他这种跨学科的灵感、问题视角,得益于什么样的研究方法和学术成长模式?
最近,带着这些问题,智源社区编辑采访了史作强老师。
整理:王炜强,常政
01
数学之美:
抽离现实,理解现实
智源:您从何时开始对数学产生了兴趣?数学的哪些特质吸引了您?
史作强:很多人可能自小就对数学保有浓厚的兴趣,但我并不是,甚至我高考的第一志愿也并不是数学,而是后来“被迫”调剂到清华数学系的。随着我的学习和研究逐渐深入,我才逐渐领悟到了数学的有趣与迷人之处。这样看来,以数学作为我的职业方向颇有些误打误撞的意味。
数学给我最大的感觉是它特别地“美”。在应用数学领域,可以通过数学将一些生活中的实际问题转化成数学模型,并且用数学的方式去理解它、证明它、分析它,这对我而言是数学最大的魔力。
其实,数学与真实世界并没有直接的关联,它是人类运用智慧创造出的自成逻辑的体系,但就是这样一个抽离出现实的事物,却可以帮助我们理解现实世界,进而改造现实世界。并且,每当我完成一个数学证明的时候,也会生出十足的成就感,可能这些都是数学能够深深吸引我的特质。
智源:您从2011年开始在清华大学任教,您在清华的主要研究方向是什么?取得了哪些研究成果呢?
史作强:我从攻读博士起就一直从事偏微分方程及其数值方法相关的研究工作,来到清华之后主要研究流形上偏微分方程的数值方法。
概括来讲,我近年来的产出主要围绕在所谓的流形,或称“点云”上求解偏微分方程的数学方法,及其在人工智能、机器学习、数据分析中的一些问题应用。比如用低维流形模型(Low Dimensional Manifold Model),来描述描述高维数据空间中的低维结构等。
02
流形理论:
用数学描述高维数据中的低维结构
智源:从数学理论到机器学习,一直研究数学的您又因何会对人工智能产生兴趣?
史作强:与人工智能结缘是在2016年,我曾去UCLA(加州大学洛杉矶分校)访问。在这个过程中,我发现之前研究的理论和方法,都可以在图像分析领域、数据分析领域得到应用。此后我就开始进行机器学习、人工智能方面的问题研究,再加上这两年我又发现偏微分方程与深度学习、神经网络存在一定的关系,所以我在人工智能问题上的研究也就更加走向了深入。
智源:流形理论、偏微分方程与机器学习之间具体存在哪些联系?
史作强:用流形理论结合偏微分方程来研究机器学习,是近年来学术界一个很新颖的视角,它有望对机器学习、深度学习进行更有效率地优化建模,分析、构建人工智能算法中的一些基本理论等。
以一个最经典的图像分类问题为例,我们先假设一个简单的模型:每一幅图像都由像素构成,那么100×100的一张图像就可以看作有1万个象素,因为每一个像素反映在计算机中都是一个数,所以这幅图片将通过计算机中的1万个数来表示。从几何的角度,这1万个数可以看作是1万维空间中的一组坐标,比如一副100×100的猫或狗的图片,可以被表示成1万维空间中的一个点。在如此高维的空间中,即使我们有再大量的数据也不可能塞满这个空间。我们可以想象一下,如果每个维度放两个点,要充满这个1万维空间的话,实际上需要放2的1万次方个点——这样大的数量级是计算机根本处理不了的。一种普遍的想法是,我们要研究的数据实际上落在了这个高维空间中的某种低维结构上面它包含的少量特征其实已经足以刻画诸如猫、狗图这样的研究对象了。寻找这种特征结构的过程,便是机器学习领域说的Dimensionality Reduction(降维),而流形理论正好可以提供一套有用的工具,能比较好地通过数学化的语言来描述高维数据空间里面的一些低维结构。同时根据我们的研究发现,如果再将偏微分方程结合进来,可以更好地研究流形结构,进一步揭示隐藏在数据中的各种信息。所以我们认为它们是研究机器学习问题和理论的一个非常好的切入点。
03
流形+偏微分:
AI算法的“稳定剂”和“扩散剂”
智源:您准备用流形结合偏微分方程来解决人工智能的哪些具体问题?它们可能带来哪些应用?
史作强:我们希望来解决目前“对抗攻击”和“半监督学习”中的问题。
首先来看对抗攻击。近年来,人们发现神经网络在一些场景中的稳定性不佳,这里有个很著名的案例:一幅熊猫的图像,即使加上一点小小的、肉眼看不出的扰动,神经网络都可能在判别中出现错误(如图1)。这就是所谓的神经网络在对抗攻击下的不稳定性。由于神经网络的不稳定性,他人可以有针对性地设计所谓的攻击方法,导致其发生判别错误。对抗攻击在自动驾驶或者安全等领域是很致命的问题,比如一些交通指示牌,可能只是被加上一些小泥点,便可能导致训练出来的神经网络发生判断错误。
图1:细小扰动导致“大熊猫”被识别成“长臂猿”
在对抗攻击问题中,我们采用流形结合偏微分方程来建模,是因为发现神经网络和物理学中的对流方程,有十分相似的特性。比如对流方程描述的空气对流,是很复杂、混乱的,甚至可能产生湍流等,这就对应了神经网络的不稳定性如果把这个神经网络的输出看作一个函数f(x),x即使进行很小的变化都会对f(x)产生很大的影响,从数学的角度来说,则说明函数f(x)实际上可能产生了类似跳跃的性质。所以我们可以借鉴物理学中对流方程的思路,从偏微分方程的角度,添加一个扩散项(或称“黏性项”)来抑制奇异性,让解更加光滑,从而提升神经网络的稳定性。从流体的角度来理解,好比空气、水容易产生湍流,但黏性较高的沥青便很难发生。用偏微分方程建模,举例来说,最简单的黏性项就是所谓的拉普拉斯算子(Laplace Operator)。
对于半监督学习,我们的思路是研究有标记样本和无标记样本之间的关联,然后基于这个关联,将标记的信息从标记的样本散播到没有做标记的样本中去。这个过程,我们同样用偏微分方程进行建模,通过它的扩散项构建出要一个标记的扩散模型。这好比标记的内容,相当于某种流体物质的浓度,当我对这种物质设置了一定的条件后,它就慢慢地扩散出去。如果有标记内容和无标记内容的关联比较强,它扩散的速度就会比较快,反之就比较慢等。
智源:据您所知,在目前国内外学者中,利用流形理论和偏微分方程解决人工智能问题取得的主要进展有哪些?您现在的研究有什么创新之处?
史作强:目前在国内外,用流形研究人工智能的学者有一些,但是利用偏微分方程来研究的人较少。前些年,机器学习领域与偏微分方程相关的研究主要集中在椭圆方程在半监督学习中的应用。近年来随着最优输运(Optimal Transport)理论在机器学习中的发展,与其相关的偏微分方程也逐渐引起了很多关注。
我们和其他学者最大的不同,就是把流形跟偏微分方程结合起来进行研究,我们目前取得的进展主要集中在对抗攻击上,我们去年在NeurIPS上发表了一篇有关利用偏微分方程研究对抗攻击的论文[1],其结论是我们的算法确实可以提高神经网络的稳定性,比当时报道的最好方法还能提高2到3个百分点。此外,在前年发表的一篇文章里[2],我们利用这个偏微分方程与神经网络的一些联系,将原来的神经网络进行了一些改动,也呈现出了较好的结果。
智源:您认为在当前的研究中,面临的主要问题和挑战是什么?你希望智源研究院能在哪些方面给与更多支持?
史作强:主要挑战是它需要很丰富的知识储备,尤其是在机器学习、人工智能这些充满交叉的学科领域,我们在研究过程中会发现它们与其他很多事物都有联系,如随机偏微分方程与优化、动态规划等知识存在联系。所以我非常希望在智源研究院里能够找到相关领域的专家学者,向他们请教或者进行合作研究。
04
学术交流:
注重培育发散型思维
智源:在您的研究经历中,最让您受益的研究方法是什么?
史作强:对于应用数学这样一门交叉学科,我们作为研究人员,一定要重视发散型思维的训练,我们正在研究的世界其实很神奇,它有很多看似无关的内容,实际上是可以彼此联系的,比如偏微分方程可以同深度学习、神经网络联系在一起。
培育发散性思维的方法,首先要多读多看,形成一定量的知识储备;其次是开展工作时一定要有开放的心态,不能固步自封、自我限制,不能因为自己只从事某个研究方向就对其他领域不闻不问。
智源:您平时主要通过哪些方式与其他学者进行学术交流?其中哪些方式会让您比较受益?
史作强:对于学术交流,我主要通过这些方式:参加国内外的学术会议和各类活动;出国做访问学者,或者邀请别人来进行访问。对我个人而言,外出交流更加让我受益,较为典型的就是去UCLA做访问学者的那次经历。
我共有两次在国外研究的经历,第一次是在加州理工大学做博士后,第二次是去UCLA做访问学者。加州理工和UCLA都是举世闻名的学校,但风格却各有不同。加州理工的风格是小而精,其学生、老师数量都很少,当时我所在的院系只有四五个教授,且每个教授的团队也都不大,所以那时候的交流主要是与老师进行的一些交流。比如当时应用数学有一个非常热门的研究领域叫压缩感知(Compressed Sensing),其代表人物Emmanuel Candès 恰好和我同在一个系,这使得我比较早地接触到了压缩感知方面的知识。
UCLA的风格正好与加州理工大学相反,其研究团队比较大,包含了各类研究领域的学者。在那里,尽管研究组的指导教授和大家交流不多,基本上两、三周开一次讨论会,但我获得了大量和研究组里其他学者们(包括老师、博士后、博士生等)互动的机会。他们的学术背景迥异,包括纯数学、计算数学、计算机和生物等不同学科,使得你无论想研究什么,总能方便地找到相关的学者来激发你更多的思考。大家平时交流的时候,基本也没有什么特别的目的性,主要是通过吃饭、出去活动等形式在一起闲聊,但就是在这样不经意且密切的互动中,往往会让你在某一天脑海里突然产生一些新的想法。
智源:您觉得国内的学术交流跟国外相比,有哪些特色或不同?您心目中理想的学术交流模式是什么样的?
史作强:我觉得国内的学术交流,有时候目的性更强一点,比如“我有个什么问题,看看你能不能解决?”像在进行某个工程问题的技术攻关等。当然了,在一些场景下确实是需要明确目标、大家集中力量解决某个问题,但就我们所研究的领域来说,我觉得在一种相对轻松、发散些的目标氛围下,大家一起头脑风暴更容易碰撞出一些好的思想火花。
04
寄语青年学子:
到最顶尖的平台去
智源:请史老师结合您自己的经历和成功经验,给现在的青年学者、学生们提几个学术成长方面的建议。
史作强:我认为对于学术成长而言,最重要的是能够到你从事的研究方向最顶尖的地方去访问,只有跟着最顶尖的人做一些研究,对自己的成长才是最有帮助的。跟着最顶尖的人做研究,一方面他能帮助你开拓视野,在与他们的交流过程中,你会发现他们看问题的角度与他人并不一样,他们往往能够站在更高的层次上;另一方面,只有最顶尖的人才能领导最顶尖的团队,最顶尖的团队里各种不同学科背景的人在一起工作,很容易就会产生思想的碰撞,也有助于自己借鉴别人的一些想法,从而产生一些新的研究思路。
在这方面,我感觉自己非常幸运。我在加州理工学院从事博士后工作之时遇到了侯一钊老师,随后我在UCLA访问的时候,遇到了应用数学界非常著名的Stanley Osher教授,这两位老师对我的帮助非常大。
侯老师非常擅长鼓励年轻人探索一些他认为较为重要的课题方向。应用数学是一个非常大的领域,在我当时还没有太多经验,有点迷失其中的阶段,恰好遇见了侯老师,他扮演了我的指路人角色,使得我的未来之路一下子清晰了。
Stanley Osher教授则给年轻人创造了一个非常开放、有利于成长的学术平台。Stanley Osher 本人在应用数学领域就是一个传奇人物,他涉猎广泛:从早期的流体计算、到图像处理,再到现在的深度学习、机器学习等,其传奇之处在于他研究的每一个问题,后来均被证明为该领域最重要的问题之一,甚至引领出一个学术潮流。他在学术上具有十分敏锐的直觉,善于直击问题的要害,他主持的研究团队,在他的影响下显得思想颇为开放,氛围很轻松,非常适合做应用数学的交叉研究。
点击上方“蓝字”关注我们
协同过滤( Collaborative Filtering)
Mar 26, 2020
本期介绍推荐系统中的协同过滤方法。
本文约3k字,预计阅读18分钟。
「基于用户行为」设计的推荐算法,即协同过滤,从字面上理解,包括协同和过滤两个操作。所谓协同就是利用群体的行为来做决策(推荐)。对于推荐系统来说,通过用户的持续协同作用(与网站不断进行互动),最终给用户的推荐会越来越准确。而过滤,就是从可行的决策(推荐)物品中将用户喜欢的物品找(过滤)出来。
具体来说,协同过滤的思路是通过群体的行为来找到某种相似性(用户之间的相似性或者物品之间的相似性),通过该相似性来为用户做决策和推荐。
协同过滤有「基于邻域的方法(neighborhood methods)」、「隐语义模型(latent factor model)」、「基于图的随机游走方法(random walk on graph)」等。基于邻域应用最为广泛,主要包含两种算法:
基于用户的协同过滤算法:给用户推荐和他兴趣相似的其他用户喜欢的物品(图左)
基于物品的协同过滤算法:给用户推荐和他之前喜欢的物品相似的物品(图右)
因此协同过滤的核心是怎么计算物品之间的相似度以及用户之间的相似度。相似度系数可以衡量用户或物品之间的相似度。
基于物品的协同过滤
基于用户的协同过滤算法的简单定义:在一个在线个性化推荐系统中,当一个用户A需要个性化推荐时,可以先找到和他有相似兴趣的其他用户,然后把那些用户喜欢的、而用户A没有听说过的物品推荐给A。
故该算法主要分为两个步骤:
找到和目标用户兴趣相似的用户集合;
找到这个集合中的用户喜欢的,而目标用户没有听说过的物品推荐给目标用户;
用户相似度计算 可以利用「Jaccard公式」和「Cosine相似度」来简单的计算用户 和 之间的相似度,另外相似度系数常用的还有「Pearson相关性系数(Pearson Correlation)」。
Jaccard系数用于计算两个集合之间的相似度,比较适合隐式反馈类型的用户行为。
Cosine相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似性"。
Pearson相关性系数是衡量向量相似度的一种方法。输出范围为[-1, +1], 0代表无相关性,负值为负相关,正值为正相关。
以隐式反馈为例, 表示用户 用过正反馈的物品集合, 表示用户 用过正反馈的物品集合,公式如下:
Jaccard:
Cosine相似度:
物品得分计算 得到用户之间的兴趣相似度后,算法会给用户推荐和他兴趣最相似的K个用户喜欢的物品。如下公式度量了用户 对物品 的感兴趣程度:
其中 包含和用户 兴趣最接近的K个用户, 是对物品 有过行为的用户集合, 是用户 和用户 的兴趣相似度, 代表用户 对物品 的兴趣(或评分)。(若为隐式反馈,则 )
有了用户对每个物品的评分,基于评分降序排列,就可以取top-K推荐给用户了。
基于用户的协同过滤
基于用户的协同过滤算法的缺点是随着网站的用户数目越来越大,计算用户的兴趣相似度矩阵将越来越困难。故由亚马逊提出了另一个算法---基于物品的协同过滤算法。
基于物品的协同过滤算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算物品之间的相似度。
该算法认为:物品A和物品B具有很大的相似度是因为喜欢物品A的用户大都也喜欢物品B。
同理,基于物品的协同过滤算法主要也分为两步:
计算物品之间的相似度;
根据物品的相似度和用户的历史行为给用户生成推荐列表;
物品的相似度计算同用户的相似度计算。
用户 对物品 的兴趣:
HTML基础知识 HTML的历史:HTML,XHTML HTML的全局属性:全局标准属性,全局事件属性 HTML的元素: 标记语言,是一种将文本以及与文本相关的其他信息结合起来,展现出关于文档结构和数据处理细节的电脑文字编码。 HTML,为超文本标记语言。 XHTML是可扩展超文本标记语言,是一种更纯洁,更严格,更规范的 html代码。 html文件由文件头和文件体两部分组成。 标签的分类:双标签,单标签。 双标签:由“开始标签”和“结束标签”两部分构成,必须成对使用,且必须合理嵌套。
单标签:在开始标签中进行关闭(以开始标签的结束而结束)。
HTML的全局标准属性 在HTML中,规定了8个全局标准属性。
class用于定义元素的类名。 id用于指定元素的唯一 id。 style用于指定元素的行内样式。 title用于指定元素的额外信息。 accesskey用于指定激活某个元素的快捷键。 支持accesskey属性的元素有<a>, <area>, <button>, <input>, <label>, <legend>, <textarea>。
tabindex用于指定元素在 tab键下的次序。 支持tabindex属性的元素有<a>,<area>,<button>,<input>,<object>,<select>,<textarea>
dir用于指定元素中内容的文本方向。 dir的属性值只有ltr和rtl两种,分别是left to right和right to left。
lang用于指定元素内容的语言。 HTML的全局事件属性 Window窗口事件 onload,在页面加载结束后触发。 onunload,在用户从页面离开时触发,如单击跳转,页面重载,关闭浏览器窗口等。 Form表单事件 onblur,当元素失去焦点时触发。 onchange,在元素的元素值被改变时触发。 onfocus,在元素获得焦点时触发。 onreset,当表单中的重载按钮被点击时触发。 onselect,在元素中文本被选中后触发。 onsubmit,在提交表单时触发。 Keyboard键盘事件 onkeydown,在用户按下按键时触发。 onkeypress,在用户按下按键后,按着按键时触发。 该属性不会对所有按键生效,不生效按键如:alt,ctrl,shift,esc。
onkeyup,当用户释放按键时触发。 Mouse鼠标事件 onclick,当在元素上单击鼠标时触发。 onblclick,当在元素上双击鼠标时触发。 onmousedown,当在元素上按下鼠标按钮时触发。 onmousemove,当鼠标指针移动到元素上时触发。 onmouseout,当鼠标指针移出元素时触发。 onmouseover,当鼠标指针移动到元素上时触发。 onmouseup,当在元素上释放鼠标按钮时触发。 Media媒体事件 onabort,当退出媒体播放器时触发。 onwaiting,当媒体已停止播放但打算继续播放时触发。 HTML元素 一个HTML文档包含的标签
<!DOCTYPE>,声明文档类型。 <html>,HTML元素真正的根元素。 <head>,定义 html文档的文档头。 head中包含的元素
1. 实现效果 在阅读外文PDF时,需要复制文字,会发现粘贴出来的文字都出现很奇怪的换行。
使用该Python脚本,可直接替换掉 剪切板 内的换行。再 Ctrl + V,完美。
2. 脚本代码 改自:CSDN博客(Windows下利用win32clipboard实现Python的剪切板(Clipboard)操作)。
修改:中文windows下中文输出乱码。
原理:
1. Python3 默认编码是unicode,Windows环境默认是gbk编码。二者需要转换。
2. 从剪切板取字符串时,python3 会自动将文字以 utf-8 的编码保存到内部,所以再发送给 剪切板之前,要显式转为 gbk,再递给剪切板。否则会出现:英文正确,而汉字乱码的奇怪情况。
3. 此代码需自行安装 pywin32 库。(太久已忘当时如何装的了,可以试试CMD命令:pip3 install pywin32 )
# clipboard.py #coding:utf-8 import win32clipboard as wc import win32con def stripClipboard(): # 开始剪切板操作 wc.OpenClipboard() # 尝试将剪切板内容读取为Unicode文本 txt = wc.GetClipboardData(win32con.CF_UNICODETEXT) #用unicode读 txt = str(txt).strip() # 字符串按行分割 txt = txt.splitlines() n = len(txt) # 用空格拼接每行 txt = ' '.join(txt) # 将所有长度大于1的空白符转为1个空格 txt = ' '.