精华内容
下载资源
问答
  • Python 爬虫系列教程爬取批量百度图片

    万次阅读 多人点赞 2018-07-29 19:40:05
    很久之前就学习了Python的...当你需要下载大量图片的时候,或许你会去百度图片里一张右键下载,但这样未免太麻烦了,有了这工具,你直接运行下程序,输入你想要下载图片的关键字,然后输入你想要下载图片的数...

    很久之前就学习了Python的爬虫了,也用来做过一些项目(主要是一些课程项目),但时间比较紧,一直没有空把它写下来,这个暑假,我可能会逐渐更新Python爬虫的相关知识。

    项目1:实现批量爬取百度图片

    先简单的介绍下这个项目。当你需要下载大量图片的时候,或许你会去百度图片里一张张右键下载,但这样未免太麻烦了,有了这个工具,你直接运行下程序,输入你想要下载图片的关键字,然后输入你想要下载图片的数量,你就成功下载图片了!

    下面给下演示程序的截图:

    几秒钟后,我去C盘文件夹下,就有了30张,张天爱的图片啦!

    是不是觉得,这样下载起来比较方便........

    好了,言归正传,下面开始一步步教大家,怎么实现它!

    1. Python的IDE,我想大家应该都有吧,我用的是pycharm,大家可以去官网上下载,这里顺带给大家推荐一个免费试用它的方法,当然,仅限于在校大学生(如果你是高中生的话,可能需要麻烦一点,去百度找注册码,大概每个月会更新一次的样子)

    首先,你先到jetBrains 官网,官网链接在这!打开后。

    你点击右上角的人物标志,进入账号登录页面。

    之后,你在打开这个注册账号的链接:学生账号注册链接

    点击立即申请!

    你会进入这个页面:

    这里需要一个学校的公邮,这个公邮去哪里找呢?你可以去你所在学校的官网找找,每个在校大学生都可以申请200个学校公邮的(反正我们学校是这样),你可以搜索你们学校的邮箱系统,去查看具体怎么申请,每个学校可能不同。

    申请好了以后,你在回到一开始让你进入的登录页面,登录以后,就可以免费下载使用了。

    2 .安装爬虫需要的包

     (1)如果你使用的是pycharm,那么你安装包会非常的方便,在pycharm里找的Terminal 点击,输入pip install ....就可以安装包了,当然如果是你首次运行的话,可能需要你更新pip工具,这你最好去官网重新下载下pip,这样你以后会很方便,这里就不在具体讲怎么更新pip了,以后有时间在写写吧。

     (2) 依次键入pip install BeautifulSoup  

                             pip insatll requests

                             pip install  lxml 

     (3)下面将分别介绍他们的用途:

       BeautifulSoup 是用来获取一个页面里面的各个标签及里面的内容,我们主要用到它里面的find(),find_All()函数,具体用法将在后面一一介绍

      requests 是用来获取网页信息的,也就是说,我们给它一个url,它能把这个url对应的页面信息全部反馈给我们,这时候我们在用beautifulSoup里的函数对他们进行处理

    lxml 是一个解析器,python里有专门的解析器,html.parser,但是lxml的解析速度优于html_parser,所以建议使用lxml

    3. Python正则表达式基础

      要想提升写爬虫的能力,那么你必须学会正则表达式,它可以让你用简短的代码实现你想要的功能。

    详细的知识,可以到这里去看.python 正则表达式

    下面我会介绍,本次项目里使用到的技巧:

    首先你先打开百度图片 ,也就是这个页面 百度图片

    然后,你可以随便输入你想要查看的图片....(不好意思,我还是输入了,zhang tian ai)

     

    注意:先点击右上角,切换成传统翻页版,因为这样有利于我们爬取图片!这里一定要注意,很多网友问我,为啥他打开百度图片,每一页不是60张图片。因为你直接打开的网页,不便于翻页操作,并且每一页的图片数量不相同。所以,我选择爬取的方法是,从传统翻页版爬取图片。

    接着,你右键检查网页源代码(如果你用的是谷歌浏览器),那么你可以在里面直接搜索 objURL 或者URL

    现在我们发现了我们需要图片的url了,现在,我们要做的就是将这些信息爬取出来(网页中有objURL,hoverURL...但是我们用的是objURL,因为这个是原图),如何获取objURL?当然你可以暴力写个程序跑一遍,但是这程序写起来.....

    那我们该如何用正则表达式实现呢?其实只需要一行代码.....

    就是这么简单,我想你如果看了正则表达式,一定可以轻松的写出或者理解这句话。

    经过我的实验,我发现传统翻页版的百度图片,每一页有60张图片。这也是为啥后面我写代码,用了t+60。

    4 . BeautifulSoup知识介绍

    同样的我先给出文档链接,具体细节大家自己研究,我这里只介绍这个项目用到的知识。BeautifulSoup 文档

    我们主要用到的是find()和find_All()函数:

    5. requests 介绍

    requests文档

    requests博大精深,我们这里只不过是用了它的一个功能而已。

    html = requests.get(url) 我们将url传进去,它就会得到这个url里面的信息,具体的,大家可以在python里运行试试.

    6. 项目实现思路

     首先需要写一个下载图片的函数,其次还有检测图片数量的函数,还有最后的推荐函数(推荐函数,主要是根据你键入的文本,在百度图片里找到相似的内容,返回给用户,类似于百度搜索的最下面)

    首先是图片下载函数:下面是部分代码

    具体思路就是根据正则表达式,找到url,然后完成下载。

     

    其次是推荐函数:

    推荐函数,主要公能是把百度的相关搜索提示返回给用户,实现很简单,但需要注意编码的问题(关于python编码格式的问题,我觉得能写10000字,以后有空再慢慢写吧)。

    还有是检测图片数量函数,它的主要思路是通过计算能翻的页数来估算总数量,比如一个页面有20张图片,那么我点下一页50次,那么就说明有1000张图片....虽然这样很傻(哈哈)

    因为有些图片可能有很多张(估计要翻页10000多次),所以为了能在几秒内下载好图片,我把图片是上限设为了1020张,也就是说即使有100000张图片,我也就先告诉你只有1020张(当然你也可以把它设置为无限,可能会慢一点)

    7 主函数

    主函数主要是一些逻辑上的问题,为的就是让用户使用更便捷而已,具体我就不一一解释,我想大家看源码比看我写 的文字更有感觉。

    之前会出现下载重复的bug,现在已经解决了。

    8 源代码:

    # -*- coding: utf-8 -*-
    """
    Created on Sun Sep 13 21:32:25 2020
    
    @author: ydc
    """
    
    
    
    
    import re
    import requests
    from urllib import error
    from bs4 import BeautifulSoup
    import os
    
    num = 0
    numPicture = 0
    file = ''
    List = []
    
    
    def Find(url, A):
        global List
        print('正在检测图片总数,请稍等.....')
        t = 0
        i = 1
        s = 0
        while t < 1000:
            Url = url + str(t)
            try:
                # 这里搞了下
                Result = A.get(Url, timeout=7, allow_redirects=False)
            except BaseException:
                t = t + 60
                continue
            else:
                result = Result.text
                pic_url = re.findall('"objURL":"(.*?)",', result, re.S)  # 先利用正则表达式找到图片url
                s += len(pic_url)
                if len(pic_url) == 0:
                    break
                else:
                    List.append(pic_url)
                    t = t + 60
        return s
    
    
    def recommend(url):
        Re = []
        try:
            html = requests.get(url, allow_redirects=False)
        except error.HTTPError as e:
            return
        else:
            html.encoding = 'utf-8'
            bsObj = BeautifulSoup(html.text, 'html.parser')
            div = bsObj.find('div', id='topRS')
            if div is not None:
                listA = div.findAll('a')
                for i in listA:
                    if i is not None:
                        Re.append(i.get_text())
            return Re
    
    
    def dowmloadPicture(html, keyword):
        global num
        # t =0
        pic_url = re.findall('"objURL":"(.*?)",', html, re.S)  # 先利用正则表达式找到图片url
        print('找到关键词:' + keyword + '的图片,即将开始下载图片...')
        for each in pic_url:
            print('正在下载第' + str(num + 1) + '张图片,图片地址:' + str(each))
            try:
                if each is not None:
                    pic = requests.get(each, timeout=7)
                else:
                    continue
            except BaseException:
                print('错误,当前图片无法下载')
                continue
            else:
                string = file + r'\\' + keyword + '_' + str(num) + '.jpg'
                fp = open(string, 'wb')
                fp.write(pic.content)
                fp.close()
                num += 1
            if num >= numPicture:
                return
    
    
    if __name__ == '__main__':  # 主函数入口
    
    ##############################
        # 这里加了点
        headers = {
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
            'Upgrade-Insecure-Requests': '1'
        }
    
        A = requests.Session()
        A.headers = headers
    ###############################
    
        word = input("请输入搜索关键词(可以是人名,地名等): ")
        # add = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E5%BC%A0%E5%A4%A9%E7%88%B1&pn=120'
        url = 'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word + '&pn='
    
        # 这里搞了下
        tot = Find(url, A)
        Recommend = recommend(url)  # 记录相关推荐
        print('经过检测%s类图片共有%d张' % (word, tot))
        numPicture = int(input('请输入想要下载的图片数量 '))
        file = input('请建立一个存储图片的文件夹,输入文件夹名称即可')
        y = os.path.exists(file)
        if y == 1:
            print('该文件已存在,请重新输入')
            file = input('请建立一个存储图片的文件夹,)输入文件夹名称即可')
            os.mkdir(file)
        else:
            os.mkdir(file)
        t = 0
        tmp = url
        while t < numPicture:
            try:
                url = tmp + str(t)
    
                # 这里搞了下
                result = A.get(url, timeout=10, allow_redirects=False)
            except error.HTTPError as e:
                print('网络错误,请调整网络后重试')
                t = t + 60
            else:
                dowmloadPicture(result.text, word)
                t = t + 60
    
        print('当前搜索结束,感谢使用')
        print('猜你喜欢')
        for re in Recommend:
            print(re, end='  ')

    好了,就先写这么多。欢迎大家转载。如有问题,欢迎给我留言。

     

     

    2019年4月2日  第3次更新

    这次有网友想要爬取大量的图片作为训练材料。他想要300种不同的图片,每种100张,如果还是按之前的代码去运行,就需要他输入300次图片的名称,这样是非常浪费时间的。所以这里对代码进行一些改进,你只需要把你想要爬取图片的名称,编辑到一个txt文件,然后输入你需要的数量就行。

     

    使用方法:

    首先将你需要下载的图片名称写到一个txt文本上,文本的名字叫name即可。

    按行输入,每行放一个名字。

    将name.txt放入和你当前python文件同一目录下即可。

     

    代码:

    # -*- coding: utf-8 -*-
    """
    Created on Sun Sep 13 21:35:34 2020
    
    @author: ydc
    """
    
    import re
    import requests
    from urllib import error
    from bs4 import BeautifulSoup
    import os
    
    num = 0
    numPicture = 0
    file = ''
    List = []
    
    
    def Find(url, A):
        global List
        print('正在检测图片总数,请稍等.....')
        t = 0
        i = 1
        s = 0
        while t < 1000:
            Url = url + str(t)
            try:
                # 这里搞了下
                Result = A.get(Url, timeout=7, allow_redirects=False)
            except BaseException:
                t = t + 60
                continue
            else:
                result = Result.text
                pic_url = re.findall('"objURL":"(.*?)",', result, re.S)  # 先利用正则表达式找到图片url
                s += len(pic_url)
                if len(pic_url) == 0:
                    break
                else:
                    List.append(pic_url)
                    t = t + 60
        return s
    
    
    
    def recommend(url):
        Re = []
        try:
            html = requests.get(url, allow_redirects=False)
        except error.HTTPError as e:
            return
        else:
            html.encoding = 'utf-8'
            bsObj = BeautifulSoup(html.text, 'html.parser')
            div = bsObj.find('div', id='topRS')
            if div is not None:
                listA = div.findAll('a')
                for i in listA:
                    if i is not None:
                        Re.append(i.get_text())
            return Re
    
    def dowmloadPicture(html, keyword):
        global num
        # t =0
        pic_url = re.findall('"objURL":"(.*?)",', html, re.S)  # 先利用正则表达式找到图片url
        print('找到关键词:' + keyword + '的图片,即将开始下载图片...')
        for each in pic_url:
            print('正在下载第' + str(num + 1) + '张图片,图片地址:' + str(each))
            try:
                if each is not None:
                    pic = requests.get(each, timeout=7)
                else:
                    continue
            except BaseException:
                print('错误,当前图片无法下载')
                continue
            else:
                string = file + r'\\' + keyword + '_' + str(num) + '.jpg'
                fp = open(string, 'wb')
                fp.write(pic.content)
                fp.close()
                num += 1
            if num >= numPicture:
                return
    
    
    if __name__ == '__main__':  # 主函数入口
        
        
        headers = {
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
            'Upgrade-Insecure-Requests': '1'
            }
    
        A = requests.Session()
        A.headers = headers
        
        
        ###############################
        
        
        tm = int(input('请输入每类图片的下载数量 '))
        numPicture = tm
        line_list = []
        with open('./name.txt', encoding='utf-8') as file:
            line_list = [k.strip() for k in file.readlines()]  # 用 strip()移除末尾的空格
    
        for word in line_list:
            url = 'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word + '&pn='
            tot = Find(url,A)
            Recommend = recommend(url)  # 记录相关推荐
            print('经过检测%s类图片共有%d张' % (word, tot))
            file = word + '文件'
            y = os.path.exists(file)
            if y == 1:
                print('该文件已存在,请重新输入')
                file = word+'文件夹2'
                os.mkdir(file)
            else:
                os.mkdir(file)
            t = 0
            tmp = url
            while t < numPicture:
                try:
                    url = tmp + str(t)
                    #result = requests.get(url, timeout=10)
                    # 这里搞了下
                    result = A.get(url, timeout=10, allow_redirects=False)
                    print(url)
                except error.HTTPError as e:
                    print('网络错误,请调整网络后重试')
                    t = t + 60
                else:
                    dowmloadPicture(result.text, word)
                    t = t + 60
            numPicture = numPicture + tm
            
        print('当前搜索结束,感谢使用')

     

    如遇到bug或者有新的需求,可以给我留言。

    最新情况:由于笔者最近忙于备考,很多找我问问题的朋友我没能尽力的去帮忙。大家给我的留言我可能不能及时回复,同时很多加我微信好友的,我也不能及时回复。但我还是会抽时间尽力解决大家提出的问题。(2019.06.16)

    2019年8月4日  第4次更新

    还是有很多同学问我怎么更改每次下载的图片数量,我一开始设置的最高只能下载1060张:

    更改方法:把代码中含有1000的地方,全部换成你想要的数字。(例如每类图片都想下载5000张,那么你把1000改成5000)

    最近有很多网友留言和加我微信。我都没有回复,原因在于笔者正在备考。明年才有空。2019.11.29

     

    2020.4.13更新。

    最后在写一下,我代码里面用了t+60是因为,每一页有60张图片,我爬完一页,就代表已经获得60张图片,然后翻页,开始爬取下一页。

    另:这个项目是根据网友们的反馈,才得到不断的完善。这已经不再是我一个人的项目了,而是属于各位一起帮忙反馈bug的网友们。非常感谢各位的反馈。

    目前笔者仍然没有时间,之前收到一位网友的反馈,一直没有更新。等我5月复试结束以后,我会更新的。

    若有网友发现问题,也欢迎继续反馈给我,我后面会找时间更新的。

     

    2020.9.13

    之前遇到的问题已经解决。感谢网友们的大力支持。

     

    展开全文
  • Excel 本身没有图片居中的函数,但我们又想把每张图片居中显示在单元格,一张一张的手动去拖,既费时效果也不好,那如何做呢?

    这是【Excel 教程系列第 7 篇】,如果觉得有用的话,欢迎关注专栏。

    Excel 本身没有图片居中的函数,但我们又想把每张图片居中显示在单元格,一张一张的手动去拖,既费时效果也不好,那如何做呢?

    第一步:
    选中需要批量居中的图片(先选中一张图片,然后按住 Ctrl+A,即可全选表格内所有图片)
    在这里插入图片描述
    第二步:
    按住 Alt+F11,会弹出一个代码处理窗口,然后点击“插入→模块”
    在这里插入图片描述
    第三步:
    在输入框中粘贴下列代码
    在这里插入图片描述
    代码如下

    Sub ImageAlignment()
    
    Dim shp As Shape
    
    For Each shp In ActiveSheet.Shapes
    
    Range(shp.TopLeftCell.Areas(1).Item(1).Address).MergeArea
    
    shp.Left = (.Width - shp.Width) / 2 + .Left
    
    shp.Top = (.Height - shp.Height) / 2 + .Top
    
    End With
    
    Next
    
    End Sub
    

    提示:如果复制后每行前面出现多个问号,把所有问号删掉即可。
    然后按下 Ctrl+S 保存代码,如果提示 无法在未启用的工作簿中保存以下功能 字样,点击“是”即可。

    第四步:回到 Excel 窗口
    按住 Alt +F8 执行宏 ImageAlignment 操作。
    在这里插入图片描述
    效果图如下所示
    在这里插入图片描述
    图片较多的话可能需要稍微等待一两分钟,图片越多,等待时间越长,之后所有被选中的图片就会被居中对齐了,

    版本:Microsoft Office 2016

    你的问题得到解决了吗?欢迎在评论区留言。

    赠人玫瑰,手有余香,如果觉得文章不错,希望可以给个一键三连,感谢。


    结束语

    技术是一点一点积累的,大神也不是一天就可以达到的。原地不动就是退步,所以每天进步一点点。

    最后,附上一句格言:"好学若饥,谦卑若愚",望共勉。
    展开全文
  • (这种方法相对简单)第一个问题:在VS2013中建立好工程后,运行时提示:卷积层没有注册!解决方法:把你的工程建立在happynear大神建立的buildVS2013工程中,因为要在工程属性中配置。右击工程->属性->通用属性->...

    最近由于工作需要需要直接使用Caffe C++接口,查了很多资料后,问题终于解决。其中出现了很多问题,在这里和大家分享!今天首先介绍第一种方法用IamgeData!(这种方法相对简单)

    第一个问题:在VS2013中建立好工程后,运行时提示:卷积层没有注册!
    
    解决方法:把你的工程建立在happynear大神建立的buildVS2013工程中,因为要在工程属性中配置。右击工程->属性->通用属性->引用->caffelib->项目引用属性中全部选择True。这样在编译工程时,就没有错误提示了。但是这样的缺点是,工程不好移植,后面会继续改进。如果你有好的方法,请与我分享!大笑
    
    第二个问题:工程建立好后,下面是网络配置文件的改写,因为这里用到了ImageData数据,是把图片做为输入数据直接输入。
    

    这里写图片描述

    我们看到ImageData层与Data层没什么太大差别,是参数有变化。

    1)均值输入方式,我们当然可以使用均值文件做为均值输入。也可以使用上面的方法。上面的方法是每个通道的均值,当然还是训练数据的均值。

    2)source参数,不再是训练数据的源,而是测试阶段,也就是你想要提取特征的图片的路径和标签,标签最好注明(可随便标,因为没有用到,标注只是为了避免程序出错)

    最重要的一点就尺寸,crop_size,new_height,new_width 一定要和论文中给出的一直,我吃了大亏!谨记!

    第三个问题:网络配置文件写好,最后一步就是代码了。
    
    #include <string>
    #include <vector>
    #include "boost/algorithm/string.hpp"
    #include "caffe/caffe.hpp"
    using boost::shared_ptr;
    using std::string;
    using namespace caffe;
    using namespace std;
    
    #define MAX_FEAT_NUM 16
    
    int main()
    {
        char *deploy_net = "C:\\Users\\Administrator\\Desktop\\caffe_C++\\vgg_face\\vgg_face_deploy.prototxt";
        char *model = "C:\\Users\\Administrator\\Desktop\\caffe_C++\\vgg_face\\VGG_FACE.caffemodel";
        int iter = 1;
        std::string Blob_names = "prob";
        std::string S_filename = "C:\\Users\\Administrator\\Desktop\\caffe_C++\\result\\features";
    
        Phase phase = TEST;//测试模式
        LOG(ERROR) << "Using CPU";
        Caffe::set_mode(Caffe::CPU);
    
    
        boost::shared_ptr<Net<float> > feature_net;//定义一个网络实例
        feature_net.reset(new Net<float>(deploy_net, phase));//第一个参数 网络配置文件deploy.prototxt
        feature_net->CopyTrainedLayersFrom(model);//第二个参数,模型文件,从.caffemodel文件加载网络参数
    
        int total_iter = iter;//第三个参数,总迭代次数
        LOG(ERROR) << "Running " << total_iter << " iterations.";
    
        std::string feature_blob_names(Blob_names);//第四个参数,要提取的特征块的名字,比如fc7,fc8
        std::vector<std::string> blob_names;
        boost::split(blob_names, feature_blob_names, boost::is_any_of(","));//分割操作,分割规则,将feature_blob_names字符串分割,
        //存储到blob_names
        std::string save_file_names(S_filename);//第五个参数,保存文件名字
        std::vector<std::string> file_names;
        boost::split(file_names, save_file_names, boost::is_any_of(","));//file_names保存着 文件名(保存)
        CHECK_EQ(blob_names.size(), file_names.size()) <<
            " the number of feature blob names and save file names must be equal";
    
        size_t num_features = blob_names.size();//块的数量,从名字开始统计
        for (size_t i = 0; i < num_features; i++)
        {
            CHECK(feature_net->has_blob(blob_names[i]))//检查网络中是否有该块,blob_names[i]块的名字
                << "Unknown feature blob name " << blob_names[i] << " in the network";
        }
    
        FILE *fp[MAX_FEAT_NUM];
        for (size_t i = 0; i < num_features; i++)
        {
            fp[i] = fopen(file_names[i].c_str(), "wb");//建立多个保存文件,以写的方式
        }
    
        for (int i = 0; i < total_iter; ++i)//进入total_iter次总循环
        {
            feature_net->ForwardPrefilled();//执行一次前向过程
            for (int j = 0; j < num_features; ++j)
            {
                const boost::shared_ptr<Blob<float> > feature_blob = feature_net->blob_by_name(blob_names[j]);//net的blob指的是特征图
                float num_imgs = feature_blob->num() * total_iter;//特征块*总的循环次数=总的特征块数量
                cout << num_imgs << endl; 
                float feat_dim = feature_blob->count() / feature_blob->num();//计算特征维度
                cout << feat_dim << endl;
                const float* data_ptr = (const float *)feature_blob->cpu_data();//特征块数据
                cout << *data_ptr << endl;
    
                if (i == 0)
                {
                    fwrite(&feat_dim, sizeof(float), 1, fp[j]);
                    fwrite(&num_imgs, sizeof(float), 1, fp[j]);
                }
                fwrite(data_ptr, sizeof(float), feature_blob->count(), fp[j]);
            }
        }
    
        for (size_t i = 0; i < num_features; i++)
        {
            fclose(fp[i]);
        }
        return 0;
    }
    
    
    
    
    这个程序是引用的https://github.com/shicai/Caffe_Manual 我只是做了简单的修改和一些中文注释。
    
    到此为止,一个应用

    ImageData层,提取一张图片的特征的程序就完成了。此方法的缺点是,输入的图片只能在网络配置文件里修改,减少了程序的灵活性。本篇博客还有很多地方没有写到,以后会补上。下一篇我将介绍使用MemoryData层方法,敬请期待!

    展开全文
  • 帧动画图片系列

    2017-03-22 11:39:52
    需要练习逐帧动画的朋友,可以下载这8张图片,快速播放就是一个简单的动画
  • VGA系列:VGA显示网络图片

    万次阅读 多人点赞 2017-06-17 21:21:39
    VGA系列:VGA显示网络图片VGA系列VGA显示网络图片 1 如何用FPGA实现VGA显示 2 网络图片和VGA显示有何区别 3VGA如何显示图片

    一休哥是在读研究生的时候开始正式接触FPGA的,之所以这么说呢,是因为之前本科参加电赛的时候也学过一点FPGA的知识,可惜学习周期太短导致那次电赛惨败。可能世上就是有这么巧的事,刚上研究生的第一天,老板就给了我一块FPGA板,让我自己玩去,从此就踏上了这条不归路。
    好了,闲话不多说,接下来我们来讲讲如何用FPGA实现VGA显示网络图片。这里我们先提出几个问题,通过解决这几个问题,从而实现工程效果。
    1、 如何用FPGA实现VGA显示
    2、 网络图片和VGA显示有何区别
    3、 VGA如何显示图片

    1、 如何用FPGA实现VGA显示

    首先,我们需要清楚一个概念,VGA是一个外设模块,VGA模块有两个接口,一个接口用于连接FPGA,另一个用于连接VGA线,VGA线的另一头我们常常会与显示器相连。连接VGA线的接口一般都是一个标准VGA接口的母口。而与FPGA相连的接口有很多种,在这里,我介绍其中的一种。

    这里写图片描述

    上图就是VGA模块的硬件电路,可以看到,在图片的左边就是与FPGA相连的接口信号,一共有29个信号,我们可以大致分成三类

    • 恒定不变的信号 (VGA_BLANK,VGA_SYN)
    • 时序控制信号(VGA_CLK,VGA_HS,VGA_VS)
    • 数据信号(VGA_R[0-7],VGA_G[0-7],VGA_B[0-7])

    在使用VGA显示时我们需要将VGA_BLANK默认置1,VGA_SYNC默认置0。VGA_CLK是VGA显示的主时钟,它的频率决定了VGA显示的分辨率。VGA_HS是VGA的水平同步信号,它决定了VGA显示的宽度。VGA_VS是VGA的垂直同步信号,它决定了VGA显示的高度。数据信号中R、G、B三种颜色的小大都是8位,所以这个VGA模块显示的颜色深度为24位,也就是说VGA显示的是24位真彩色,显示的质量非常高。
    刚才提到过VGA显示的分辨率、宽度和高度。我们需要知道,VGA也是一个视频传输标准,所以VGA的分辨率也就是视频的分辨率。我们通过查看视频格式手册可以知道VGA的分辨率有哪些。在这里,我选择了一个最常见的分辨率640*480p@60Hz,这里的640、480表示水平和垂直方向的像素点个数,也就表示VGA输出了一个60Hz的640*480的视频信号。
    选择了VGA的分辨率之后,我们就可以开始着手编写程序了吗?其实不然,我们还不知道VGA显示的时序,这点我们也可以查看视频格式手册
    这里写图片描述

    在上图中,我们可以看到VGA_HS(HSYNC)信号是一个周期信号,在一个周期内,VGA_HS的低电平时间为96个VGA_CLK信号周期,高电平时间为704个VGA_CLK信号周期。VGA的数据信号在VGA_HS高电平的第49个VGA_CLK信号周期开始有效,一直持续到VGA_HS高电平的第688个VGA_CLK信号周期。VGA_VS(VSYNC)信号也是一个周期信号,在一个周期内,VGA_VS的低电平时间为2个VGA_HS信号周期,高电平时间为523个VGA_HS信号周期。VGA的数据信号在VGA_VS高电平的第34个VGA_HS信号周期开始有效,一直持续到高电平的第513个VGA_HS信号周期。为了更直观的表达这一时序,我们用下面这个图表示。
    这里写图片描述

    总的来说,其实VGA的显示时序就是一个逐行扫描的过程,每完成一个行扫描(即VGA_HS信号经过一个周期),则开始扫描下一行。只有当VGA_HS和VGA_VS同时有效,VGA数据信号才有效。
    讲完VGA的显示时序后,我们还需要计算出VGA_CLK信号的频率。我们需要按照这个公式计算:HS_total×VS_total×60Hz。
    其中,HS_total为VGA_HS信号的一个周期内包含的VGA_CLK信号周期个数,VS_total为VGA_VS信号的一个周期内包含的VGA_HS信号周期个数,分辨率640*480p@60Hz时,HS_total为800,VS_total为525。
    因此VGA_CLK信号的频率为800×525×60Hz=25.2MHz
    接下来,我们开始编写VGA的显示时序代码,我们用两个计数器hsync_cnt和vsync_cnt来实现。部分代码如下:

    /* 时序逻辑,用来给hsync_cnt寄存器赋值 */
    always @ (posedge CLK_VGA or negedge RST_N)
    begin
        if(!RST_N)                                  
            hsync_cnt <= 16'b0;             
        else
            hsync_cnt <= hsync_cnt_n;           
    end
    
    /* 组合逻辑,水平扫描计数器,在启动标志拉高后再计数,每个时钟循环递增 */
    always @ (*)
    begin
        if(hsync_cnt == `HSYNC_D - 16'h1)
            hsync_cnt_n = 16'b0;                    
        else
            hsync_cnt_n = hsync_cnt + 1'b1; 
    end
    
    /* 时序逻辑,用来给vsync_cnt寄存器赋值 */
    always @ (posedge CLK_VGA or negedge RST_N)
    begin
        if(!RST_N)                                  
            vsync_cnt <= 16'b0;                 
        else
            vsync_cnt <= vsync_cnt_n;           
    end
    
    /* 组合逻辑,垂直扫描计数器,每次水平扫描计数器计满时循环递增 */
    always @ (*)
    begin
        if((vsync_cnt == `VSYNC_R - 16'h1) && (hsync_cnt == `HSYNC_D - 16'h1))
            vsync_cnt_n = 16'b0;                    
        else if(hsync_cnt == `HSYNC_D - 16'h1)      
            vsync_cnt_n = vsync_cnt + 1'b1; 
        else
            vsync_cnt_n = vsync_cnt;            
    end
    
    /* 时序逻辑,用来给VGA_HSYNC寄存器赋值 */
    always @ (posedge CLK_VGA or negedge RST_N)
    begin
        if(!RST_N)                                  
            VGA_HSYNC <= 1'b0;                          
        else
            VGA_HSYNC <= VGA_HSYNC_N;                       
    end
    
    /* 组合逻辑,在B C D区间拉高水平扫描信号 */
    always @ (*)
    begin   
        if(hsync_cnt == `HSYNC_A - 16'h1)               
            VGA_HSYNC_N = 1'b1;                     
        else if(hsync_cnt == `HSYNC_D - 16'h1)
            VGA_HSYNC_N = 1'b0;
        else
            VGA_HSYNC_N = VGA_HSYNC;
    end
    
    /* 时序逻辑,用来给VGA_VSYNC寄存器赋值 */
    always @ (posedge CLK_VGA or negedge RST_N)
    begin
        if(!RST_N)                                  
            VGA_VSYNC <= 1'b0;                          
        else
            VGA_VSYNC <= VGA_VSYNC_N;                       
    end
    
    /* 组合逻辑,在P Q R区间拉高垂直扫描信号 */
    always @ (*)
    begin   
        if(vsync_cnt == `VSYNC_O - 16'h1 && hsync_cnt == `HSYNC_D - 16'h1)              
            VGA_VSYNC_N = 1'b1;                     
        else if((vsync_cnt == `VSYNC_R - 16'h1) && (hsync_cnt == `HSYNC_D - 16'h1))
            VGA_VSYNC_N = 1'b0;
        else
            VGA_VSYNC_N = VGA_VSYNC;
    end
    

    2、 网络图片和VGA显示有何区别

    在第一个问题中,我们知道了VGA显示分辨率为640*480,颜色深度为24位真彩色。但是,网络图片一般不会完全符合这两个参数,因此,我们需要借助一个软件工具转换一下。
    1、 首先,我们在网上随意找到一副图片。
    这里写图片描述
    这里写图片描述

    2、 可以看到这个图片的参数为分辨率为700*718,颜色深度为8位。我们用软件Image2Lcd打开该图片并设置相应参数,可以发现我们得到一张分辨率为174*179,颜色深度为8位的bmp图片。由于我使用的FPGA芯片的片内存储器资源较少,而为了将生成的mif文件顺利导入Rom IP核中,我们需要压缩图片。这里为什么要转换成bmp图片呢,因为bmp格式是非压缩的,数据格式比较简单容易处理,方便我们将这个图片存取FPGA中。
    这里写图片描述

    3、 我们知道FPGA不能直接读取图片,我们要将图片转换成mif文件,存入FPGA的rom中。因此,这里我们将制作一个包含图片全部有效数据的mif文件。这里,我们要使用另一个常用的工具MATLAB,用m语言来实现。代码如下:

    clear;  
    clc;  
    n=31146;%174*179  
    mat = imread('tu1.bmp');%读取.bmp文件
    mat = double(mat);
    fid=fopen('bmp_data.mif','w');%打开待写入的.mif文件  
    fprintf(fid,'WIDTH=8;\n');%写入存储位宽8位  
    fprintf(fid,'DEPTH=31146;\n');%写入存储深度31146
    fprintf(fid,'ADDRESS_RADIX=UNS;\n');%写入地址类型为无符号整型  
    fprintf(fid,'DATA_RADIX=HEX;');%写入数据类型为无符号整型   
    fprintf(fid,'CONTENT BEGIN\n');%起始内容  
    for i=0:n-1  
        x = mod(i,174)+1;  %174为bmp图片的水平分辨率
        y = fix(i/174)+1;  
        k = mat(y,x);
    fprintf(fid,'\t%d:%x;\n',i,k);  
    end  
    fprintf(fid,'END;\n');  
    fclose(fid);%关闭文件 
    

    3、 VGA如何显示图片

    解决了上述两个问题之后,终于可以显示图片了。
    首先,我们调用一个Rom IP核,由于我们显示的bmp图片分辨率为174*179,颜色深度为8位,所以我们设置Rom IP核如下图所示。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    如图中所示,我们设置了一个32768*8bit大小的Rom,并且使输出q受时钟控制,加入mif文件。
    VGA显示图片的代码也十分简单,我们以VGA显示有效区设置了vga_x和vga_y坐标变量,定义了两个信号用来控制产生Rom表的地址信号,与VGA显示的数据信号。由于bmp图的深度为8bit,所以我们按照332来分配红绿蓝三色数据,并将末尾置1。具体代码如下:

    assign vga_x = hsync_cnt - `HSYNC_B;
    assign vga_y = vsync_cnt - `VSYNC_P;
    
    Rom                     Rom_init
    (
        .clock          (CLK_25M            ),
        .address            (bmp_rom_add    ),
        .q                  (bmp_rom_data   )
    );
    
    //组合电路,用于生成图片位置信号
    assign  bmp_add = (vga_x >= `BMP1_X - 8'h3) && (vga_x < `BMP1_X + `BMP1_W - 8'h3) && (vga_y >= `BMP1_Y) && (vga_y < `BMP1_Y + `BMP1_H);     
    //组合电路,用于生成图片使能信号
    assign  bmp_en = (vga_x >= `BMP1_X) && (vga_x < `BMP1_X + `BMP1_W) && (vga_y >= `BMP1_Y) && (vga_y < `BMP1_Y + `BMP1_H);    
    
    //时序电路,用来给bmp_rom_add寄存器赋值
    always @ (posedge CLK_25M or negedge RST_N)
    begin
        if(!RST_N)
            bmp_rom_add <= 1'h0;
        else
            bmp_rom_add <= bmp_rom_add_n;
    end
    
    //组合电路,用于生成bmp_rom_add
    always @ (*)
    begin
        if((vga_x == `BMP1_X - 8'h3) && (vga_y == `BMP1_Y) && bmp_add)
            bmp_rom_add_n = 1'h0;
        else if(bmp_add)
            bmp_rom_add_n = bmp_rom_add + 1'b1;
        else
            bmp_rom_add_n = bmp_rom_add;
    end
    
    
    /* 时序电路,用来给VGA_DATA寄存器赋值 */
    always @ (posedge CLK_25M or negedge RST_N)
    begin
        if(!RST_N)
            VGA_DATA <= 1'b0;
        else
            VGA_DATA <= VGA_DATA_N;
    end
    
    /* 组合电路,用来生成VGA_DATA */
    always @ (*)
    begin
        if(bmp_en)
            VGA_DATA_N = {bmp_rom_data[7:5],5'b11111,bmp_rom_data[4:2],5'b11111,bmp_rom_data[1:0],6'bb111111}; 
        else if(hsync_cnt > `HSYNC_B && hsync_cnt <= `HSYNC_B + 16'd128 && vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)
            VGA_DATA_N = 24'hFF0000;
        else if(hsync_cnt > `HSYNC_B + 16'd128 && hsync_cnt <= `HSYNC_B + 16'd256 && vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)
            VGA_DATA_N = 24'hFFFF00;
        else if(hsync_cnt > `HSYNC_B + 16'd256 && hsync_cnt <= `HSYNC_B + 16'd384 && vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)
            VGA_DATA_N = 24'h00FF00;
        else if(hsync_cnt > `HSYNC_B + 16'd384 && hsync_cnt <= `HSYNC_B + 16'd512 && vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)
            VGA_DATA_N = 24'h00FFFF;
        else if(hsync_cnt > `HSYNC_B + 16'd512 && hsync_cnt <= `HSYNC_B + 16'd640 && vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)
            VGA_DATA_N = 24'h0000FF;
        else
            VGA_DATA_N = 24'd0;
    end
    

    大家可能会比较疑惑,为什么用来控制产生Rom表的地址信号bmp_add会比控制VGA显示图片的信号bmp_en 提前三个时钟 。那是因为我们在读取Rom表数据时存在延时,经过我们signaltap采集后发现,原本作为地址70的输出数据FF比地址70 慢两个时钟 ,即bmp_rom_data的输出会比bmp_rom_add延迟两个时钟,而VGA_DATA又比bmp_rom_data 延迟1个时钟 ,因此bmp_add信号需要比bmp_en 提前三个时钟
    这里写图片描述
    最后,奉上一张效果图。
    这里写图片描述

    本文所涉及的相关资料链接 :http://pan.baidu.com/s/1dFb4J65 密码:zp2r


    展开全文
  • 系列篇博客简单介绍了ImageData方法,由于该方法增加图片只能在网络配置文件里,灵活性欠佳。因此本篇博客继续上篇,介绍种更加灵活的方法,用MemoryData层输入数据,可以直接用opencv接口读入我们的图片...
  • 今天看到在之前的篇博客下有位朋友留言提到了“将多张图片拼接成多张大图”的问题,这一系列的博客已经写了三篇了,这是第四篇了,后三篇全都是基于广大博友的热心提问而成型的,十分感谢各位的关注,让我们一起...
  • 这是能从手机里选择多张图片的插件,是当时在做相机、上传图片相关的功能时在ngCordova官网看到的,下面简单介绍一下它的用法:
  • 【Photoshop】合并一系列序列帧图片成序列帧大图

    万次阅读 热门讨论 2017-10-04 10:05:51
    在2D游戏中,序列帧图片的大图是很常见很常用的东西,他...所以我们需要学会利用Photoshop合并一系列序列帧图片成序列帧大图。 一般用视频软件或者Gif处理软件导出来的帧系列图片是这样的: 你不可能拿这多达1
  • MATLAB | 生成多张图片并保存

    千次阅读 2020-08-21 14:52:28
    利用matlab快速生成多张图片并保存。 %% Title: Image Generator % Author: 羽墨志(https://yumozhi.com/) % Date : 2020-08-21 %% Introduction % 按需求生成多张图片并保存到指定文件夹下 % 如生成64张480*...
  • Python拼接多张图片

    千次阅读 2016-05-23 11:31:32
    写机器学习相关博文,经常会碰到很多公式,而Latex正式编辑公式的利器。目前国内常用的博客系统,好像...然后,修改部分HTML不支持的Latex源码,使得最后的博文跟我生成的PDF文档几乎摸一样。这里面设计到图标的引用,
  • Django Admin 上传多张图片并显示缩略图 1.效果预览 需要的python库:因为要处理图片,必须安装pillow库。 2.自定义Widget django Admin使用的图片上传Widget是: <input type='file'> 非常丑陋,...
  • 可以进行图片的多选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 。很不错的源码,大家有需要可以下载看看 。 如果不知道如何上传文件,参考: ...
  • 【图片】批量获取几万张图片

    千次阅读 2017-06-07 09:58:00
    代码用途:需要图片时我们经常是去百度里随便找几张,次数多了就有点烦了,这工具类就是批量获取几万张图片的url和描述。public class PicUrls { private static final String HOST0 = ...
  • 1、设置组件风格 ... 如果是按键、设置按键的背景色和边框 /*设置组件的风格*/ Component { id: btnStyle; ButtonStyle { /*设置按键背景色*/ background: Rectangle { impl
  • Python爬虫系列图片采集

    千次阅读 2018-11-11 19:45:19
    今天的一个爬虫小例子,图片爬取,从目录到目录内部图片,适合于批量类似图片的抓取 所有爬虫仅仅为技术交流,没有任何恶意,若有侵权请☞私信☚ 注意:请掌握合适的下载速度,防止ip频率过高 详情查看代码注释...
  • 因为是从这一系列篇的开头,是说整个python3爬虫的一个架构,但是后面几篇例子呢,写的文章也没有这么多复杂的文件,于是决定开一篇,对着具体的流程介绍这个: python3爬虫系列01之结构:爬虫整体架与常用模块库...
  • 你将学到 拍照并通过canvas标签获取图片数据. 与远程用户交换图片数据.
  • 这58张图片,能让你笑出块腹肌!

    千次阅读 多人点赞 2019-02-05 22:00:00
    【1】Java VS C++【2】功能先上了再说【3】高级开发人员作为一个团队进行编程【4】调试CSS【5】高级开发人员重构代码【6】能一个手指完成的绝不用两只手【7】看...
  • 最通俗的例子,古人的藏头诗就是隐写的种方式: 而CTF图片隐写术就是利用图片来隐藏一些机密信息,一张看起来很正常很普通的图片其实内部隐藏了其他玄机。 图种(多文件压缩) 所谓图种,就是先把要想...
  • Android性能优化系列之Bitmap图片优化

    万次阅读 多人点赞 2017-04-01 00:26:23
    在Android开发过程中,Bitmap往往会给开发者带来一些困扰,因为对Bitmap操作不慎,就容易造成OOM...1.每个机型在编译ROM时都设置了一个应用堆内存VM值上限dalvik.vm.heapgrowthlimit,用来限定每个应用可用的最大内
  • 从多张图片重建3D模型(瞎七瞎写了好多)

    万次阅读 多人点赞 2017-10-23 14:28:15
    1.2 SFM:对多张图片像素做匹配对应,通过上步得到的特征,从而估计相机参数,得到稀疏的3D信息 1.3 CMVS/PMVS:根据上步得到的相机参数,做稠密重建,得到点云 1.4 对上步的点云做后处理,得到网格,去除噪声点等。...
  • Android-ImagesPickers是一个图片选择(单选/多选)、拍照、裁剪、图片预览、图片显示容器的图片选择显示工具。使用方便,开发者仅需要几行的代码就可以集成Android整套图片“选裁显删”功能,可以通过设置参数...
  • python爬虫系列之基于requests:根据关键词自动爬取下载百度图片 1.前言 在上篇文章当中,我们已经分析过了百度图片的搜索URL的变化,发现关键词就在搜索结果页的网址中。我们只需要把网址中的关键词换掉,就是...
  • 描述:后台商品编辑时,页面:上传图片,设置图片主图,以及删除图片,后台:保存图片到图片服务器,返回完整... 商品图片(最多可添加10张图片,建议图片尺寸600*600px,大小≤6MB,支持JPG、PNG、JPEG) 共 0 张
  • 自定义 View 实现一个图片显示控件

    千次阅读 2018-08-10 16:51:52
    博主声明: 转载请在开头附加本文链接及作者信息,并标记... 我们来学习一下如何自定义一个自己ImageView,当然也是从最基础开始,我们只需要可以显示图片就好了。目的是基于此例子来熟悉我们自定义View的一些操作...
  • 猫狗数据集:https://pan.baidu.com/s/13hw4LK8ihR6-6-8mpjLKDA 密码:dmp4 代码 对于猫狗数据上的训练,存在一点问题在与不能够将所有的训练集读入到内存,这时候需要用到keras中的 model.fit_generator()  ...
  • Drawable Animation 可以让我们按顺序加载一系列的资源来创建一个动画。动画的创建和传统意义上电影胶卷的播放一样,是通过加载不同的图片,然后按顺序进行播放来实现的。在代 码的实现上 AnimationDrawable 类是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 73,734
精华内容 29,493
关键字:

一个系列的八张图片