在上公共的编程基础课时,我们经常受到学生的质疑: 我们学这玩艺儿有什么用? 学生的疑问来自于“他没有从课程中得到通过程序设计来解决本专业问题的体验”。重庆大学的教学团队设计了很多与各专业紧密相关的程序设计案例,我们会陆续分享出来,供大家参考。

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

(在原始案例中,代码中间留空让学生填写,这里的代码是完整的)

一幅细胞照片经过二值化以后可以视为像素值为0或1的矩阵,如图21-1所示。在该矩阵中,值为1为元素表示该处是细胞或细胞的一部分,该元素的上、下、左、右的相邻元素如果也是1,则相邻元素与该元素位于同一个细胞内;矩阵中值为0的元素表示该处无细胞。识别并统计显微镜下一幅细胞照片中的细胞数量,是血液常规检查的最基本任务之一。

对于图21-1所示的细胞照片,按上述规则,容易数出该幅照片中包含7个细胞。注意,第3行第3列是一个孤立细胞(图中已用底纹区分),它与第2行第5列的细胞并非同一个,因为它位于第2行第4列元素的左下方,而不是上下左右的位置。

在本实验对应的实验子目录中有一名为cellpicture.txt的文本文件,其内容为细胞照片的二值化矩阵。请编写程序,从该文件读取矩阵内容并统计该矩阵中的细胞数量。

该文件的内容如下:

12 14
10111000011100
01100110001101
00000111000011
00110000001000
00011000111000
00111100010011
10011101100111
11000100000001
00000000011000
00000000000000
10001100110000
10001000011111

其中,第1行的1214以空格分隔,表示该矩阵有12行14列。接下来,则是12行元素数据,每行14个0/1字符。

21.1 从文件读入二值化矩阵

下述程序负责从文件cellpicture.txt中读取二值化矩阵,并将其组织在嵌套列表d中。请将程序补充完整并运行,确保矩阵d的内容与文件一致。注意,矩阵元素的类型应为整数。

d = []
with open('cellpicture.txt') as f:m,n = map(int,f.readline().split())for x in range(m):r = list(map(int, f.readline()[:n]))d.append(r)for x in d:print(x)

【解题提示】

  • f.readline( )从文本文件f中读取一行内容,其返回值为一个字符串,注意该字符串包括了每行末尾的换行符。
  • map(func,iterable)称之为映射函数,该函数逐一将可迭代对象iterable中的元素作为参数提供给由func指定的函数来执行,映射出一系列的新元素。map()函数返回一个类型为map的可迭代对象,可以通过list()函数将其转换成列表。下述代码中的map()函数,将列表元素1,3,5,7逐一交给square()函数运行产生其平方数,再借助于list()函数转换得到包含4个平方数的结果列表。
def square(x):return x*x
print(list(map(square,[1,3,5,7])))

上述代码的执行结果为:

[1, 9, 25, 49]

21.2图的宽度优先遍历

细胞的计数依赖于对矩阵元素的遍历。在逐行逐列遍历矩阵元素的过程中,发现一个值为1的元素,则意味着新发现了一个细胞。此时,需要从该元素出发,往多个方向搜索,找出该元素归属细胞所包含的全部像素/元素,并将这些像素/元素标记为“已探索”,以避免在后续遍历过程中,这些像素被错误地认为属于一个“新细胞”。

这个任务可以通过一个称为“图的宽度优先遍历”的算法来解决,该算法可用函数explorePixel()来描述。其中,d为代表二值矩阵的嵌套列表,该矩阵有m行n列,搜索出发点为i行j列。请在阅读完解题提示后,将下述代码补充完整。

def explorePixel(d,m,n,i,j):q = [(i,j)]while q:x,y = q.pop(0)if d[x][y] < 0:continue d[x][y] = 0-d[x][y]if x>0 and d[x-1][y]>0:q.append((x-1,y))if x<(m-1) and d[x+1][y]>0:q.append((x+1,y))if y>0 and d[x][y-1]>0:q.append((x,y-1))if y<(n-1) and d[x][y+1]>0:q.append((x,y+1))

【解题提示】

  • explorePixel( )函数的任务可以描述为:从位于i行j列的像素出发,向其周边进行搜索,将与该像素有连接关系的其他像素全部找出,并标记为“已探索”。

  • 当像素值=0时,该像素不属于细胞;像素值=1时,该像素属于细胞且“待探索”,像素值=-1时,该像素属于细胞且“已探索”。

  • 列表q的行为表现为一个先进先出队列,其中存储那些已发现,但其自身及其相邻像素尚未被探索的像素。最初,q仅包含像素(i, j)。然后,程序将一直循环,直至队列空为止,每次循环的过程如下:
    (1)从队列中取出第0个待探索的像素(x, y);
    (2)检查(x,y)是否为已探索,如是,continue进入下一轮循环;
    (3)将(x,y)标记为“已探索”,即将其值变更为 0– d[x][y];
    (4)按上、下、左、右的顺序检查(x,y)的相邻像素,如果相邻像素的值>0,说明该相邻像素也属于当前细胞,将其加入待探索像素队列q。

  • 函数中的x表示行坐标,y表示列坐标。即与平面坐标系的通常习惯有所不同,这里的x表示上下方向,y表示左右方向。

为帮助读者理解上述“图的宽度优先遍历”算法,我们手工模拟一遍explorePixel()函数的执行过程,从像素(0,4)出发。请见图21-2,为了与程序一致,我们的行号、列号改为从下标0开始。

当程序遍历矩阵元素到第0行第4列时,发现像素(0,4)值为1,即该像素状态为待探索且属于一个新细胞,执行explorePixel(d,m,n,0,4)从像素(0,4)出发搜索与该像素连接的全部细胞像素:
(1) 队列q被初始化为只包含像素(0,4),其值为:[ (0,4) ]。
(2) 像素(0,4)出队列,其值等于1待探索,像素(0,4)被赋值-1。
此时,q = 空列表。
(3) 像素(0,4)位于第1行,其上方元素不存在。
(4) 像素(0,4)的下方元素(1,4)的值为1,属于同一细胞,将(1,4)加入队列q。
此时,q = [ (1,4) ]。
(5) 像素(0,4)的左方和右方元素值为0,不属于细胞。
(6) 像素(1,4)出队列,其值等于1待探索,赋值-1。
此时,q = 空列表。
(7) 像素(1,4)的上方元素(0,4)此时值为-1已探索。
(8) 像素(1,4)的下方元素(2,4)值为1,属于同一细胞,加入队列q。
此时,q = [ (2,4) ]。
(9) 像素(1,4)的左方和右方元素值均为1,属于同一细胞,将左方元素(1,3)和右方元素(1,5)加入队列q。
此时,q = [ (2,4), (1,3), (1,5) ]。
(10) 像素(2,4)出队列,其值为1待探索,赋值-1。
此时,q = [ (1,3), (1,5) ]。
(11) 像素(2,4)的上方元素已探索,下方、左方、右方元素为0,故未发现新的待探索像素。
(12) 像素(1,3)出队列,其值为1待探索,赋值-1;(1,3)的右方元素已探索 ,上方、左方、下方均为0,故未发现新的待探索像素。注意,(2,2)位于(1,3)的左下方,并不属于题目定义的相邻像素。
此时,q = [ (1,5) ]。
(13) 像素(1,5)出队列,其值为待探索,赋值-1;(1,5)的左方元素已探索,其它三个方向均为0,未发现新的待探索元素。
(14) 此时,q = 空列表,循环结束。在循环过程中,(0,4)、(1,4)、(2,4)、(1,3)、(1,5)共5个像素被探索并标记为已探索,这5个像素构成了一个完整的细胞。

            if d[x][y] < 0:continue

读者可能会上述两行代码感到疑惑:既然一个待探索元素在加入队列前其值确定为1即待探索,那么在该像素出队后,其值可能变为负数(已探索)吗?

我们考虑图21-3所展示的情况。当我们从(1,1)出发搜索该细胞的全部像素时,(2,2)作为像素(2,1)的相邻元素,在探索(2,1)时会被加入队列。同时,作为(1,2)的下方元素,在探索(1,2)时也会被加入队列。这样,队列中就会存在两个(2,2),当第1个(2,2)被取出时,其像素值为1未探索,而当第2个(2,2)被取出时,其像素值已经是-1已探索。此时,再去考虑(2,2)的相邻元素已不具实践意义,故略过。

21.3 循环遍历与搜索

在实现了函数explorePixel( )之后,下述程序逐行逐列地遍历全部矩阵元素,如果发现值>0的像素,说明遇到了一个属于细胞且“待探索”的元素,将细胞计数变量iCellCount加1,然后再调用explorePixel()函数从该像素出发探索整个细胞。由于explorePixel( )函数会将所有探索过的细胞像素置为已探索,所以当下述程序第2行、第3行的主循环遍历到已探索的细胞像素时,该像素值为-1,不会将其视为一个新细胞。

请将下述程序补充完整,并与前两小节的程序合并,运行,识别并统计cellpixel.txt文件中的细胞个数。

iCellCount = 0
for i in range(m):for j in range(n):if d[i][j] <= 0:continueiCellCount += 1explorePixel(d,m,n,i,j)print(iCellCount)

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++

Python编程基础及应用

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程

Python生物医学专业案例 - 细胞计数相关推荐

  1. python 查询sqlserver 视图_SQL Server 2017 数据库教与学(教学大纲,含Python+SQL Server案例)...

    原标题:SQL Server 2017 数据库教与学(教学大纲,含Python+SQL Server案例) 本书提供Python+SQL Server案例 SQL Server教学大纲 一.课程的性质 ...

  2. Python视频处理案例六则:旋转视频、调整音量/播放速度、淡入淡出、插入转场素材...

    封面图片:<Python程序设计基础与应用>(ISBN:9787111606178),董付国,机械工业出版社 图书详情: ============== 环境配置请参考:Python视频处理 ...

  3. Python花式编程案例集锦(9):sorted()函数中消失的cmp参数

    明天开启全国巡讲Python模式,连续8场20天讲课,外加路上来回大约16天,这个假期有的忙了.所以接下来的一段时间里不一定能像以前更新的那么频繁,我尽量. 在很久很久很久以前,公众号曾经推送过这样一 ...

  4. python与办公自动化案例_Python办公自动化让工作更轻松

    适用人群 被重复工作所奴役的上班族,在读或者刚毕业的大学生 零基础学员建议先学习一下我们的免费Python课程 课程概述本课程包含的 Python 自动化办公的内容体系有:Python编程语言.Off ...

  5. python项目开发案例-Python项目开发案例集锦 PDF 全彩超清版

    给大家带来的一篇关于Python案例相关的电子书资源,介绍了关于Python.项目开发.Python案例方面的内容,本书是由吉林大学出版社出版,格式为PDF,资源大小99.1 MB,明日科技编写,目前 ...

  6. python开发项目案例集锦 pdf_Python项目开发案例集锦 实战项目代码+配套文件

    Python项目开发案例集锦涵盖8个开发方向.23个项目,循序渐进地让读者在实践中学习,在实践中提升实际开发能力. 全书共8篇:控制台程序.小游戏.实用小工具.网络爬虫.数据分析.人工智能.Web开发 ...

  7. python 速度 memmap_从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例

    <从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例>要点: 本文介绍了从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例,希望对您有用.如果有疑问,可 ...

  8. 转 从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例

    注: 转自 微信公众号"高可用架构":从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例 导读:Python 被很多互联网系统广泛使用,但在另外一方面,它也存在一 ...

  9. Python基础语法案例(Fibonacci):选择结构、循环结构、异常处理结构、代码优化

    推荐图书: <Python程序设计基础(第2版)>,ISBN:9787302490562,董付国,清华大学出版社,第16次印刷,清华大学出版社2019年度畅销图书 图书购买链接(京东): ...

最新文章

  1. Dynamics CRM2016 Web API之创建记录
  2. linux复制文件命令cat ,Linux学习之四(复制移动文件命令cp等及查看文本命令cat等)2017-03-28...
  3. android的窗口机制分析------事件处理
  4. 编译我的第一个c语言,linux菜鸟学习写第一个C语言代码--“hello Linux!”
  5. 单片机c语言检测压力值,基于单片机的压力检测系统设计论文.doc
  6. mysql删除新添加数据,MySQL添加、更新与删除数据
  7. 开发者硬核福利!极光可信数据云来了
  8. 电脑上怎么做pdf文件_怎么合并PDF文件?PDF合并软件哪个好?
  9. MySQL大表优化方案,单表优化、读写分离、缓存、分区表……都在这里了
  10. 同为数据分析师,有人14k,你却6k?
  11. 我是如何战胜懒惰的?
  12. GB28181协议--心跳
  13. 《人月神话》——2人月神话
  14. One Piece Introduction
  15. python信用卡客户_银行信用卡客户价值分析(Python数据分析)
  16. 蹦的一下,又来一个新属性scrollbar-gutter
  17. 远程计算机时能看吗,QQ远程控制对方电脑上的所有东西都能看见吗 – 手机爱问...
  18. 购买Blender cloud支援今年官方开源电影Gooseberry
  19. python熊猫入门
  20. H5 MediaDevices方法,调用摄像头、屏幕录像功能

热门文章

  1. 基于SpringBoot+Vue的学生成绩管理系统
  2. Mac air苹果笔记本安装Win10双系统教程(绝对能成功,超详细!)[转]
  3. matlab scope 多个图,matlab scope论文画图
  4. 小旋风asp服务器安装了还是打不开asp文件,小旋风AspWebServer - 本地架设ASP网站
  5. 什么是C++ __builtin_popcount()函数
  6. HTML乘法器制作,一种单象限乘法器的制作方法
  7. 从零开始的Nginx详解(2)【Nginx-HTTP服务器】
  8. solaris磁带机 tar 备份
  9. 知乎采集问答栏目以及文章教学
  10. 用Python读取照片拍摄的详细信息(拍摄时间、地址等)