任务 3

一家生产纽扣的工厂与您签订了合同。 重要的是工厂标识损坏的按钮,以便它们不会提供给商店。 工厂有一台照相机按钮的照片。 相机只能黑白(无彩色),分辨率不是很高很好,但这不是问题。您的工作是编写一个 C++ 程序来识别照片中任何损坏的按钮。 你需要生成一个图像,在每个按钮周围显示一个框。 如果按钮损坏,您必须显示一个红色框,如果按钮没有损坏,您必须显示一个绿色框。 请务必仔细阅读通过以下所有部分。

PS:Buttons.ppm and Ass3-start.cpp
链接:https://pan.baidu.com/s/1CmnuvId2ky2n84AN-Qihxg
提取码:k6gn

Section A - input

程序的输入是出厂时相机拍摄的照片。 这在 .ppm 文件中可用称为 Buttons.ppm。 不要以任何方式编辑此文件。
如果您不小心修改了文件,请从 Stream 下载文件的新副本。您的程序必须能够处理任何此类照片。 不要假设特定数量的按钮。不要假设按钮将始终位于照片中的同一位置。
(Hints:在开始您的程序之前,请检查 .ppm 文件是否没有错误。下载 Buttons.ppm
并将其转换为 .bmp(或其他格式)并查看它。 显示应如下所示:

只是出于兴趣 - 您可以看出相机的分辨率较低,因为图像中按钮的“阶梯”边缘。 实际上,对于许多此类问题(即识别产品缺陷),通常最好使用黑白照片,因为缺陷更明显。

Section B – understanding the problem

像许多“现实生活”系统一样,这种类型的项目永远不可能完美(这就是让现实生活变得完美的原因)
有趣的项目),但我们尽我们所能。
Notes the following:

  1. 按钮在深色背景上显示为白色(或浅灰色)物体。这是一张黑白照片,这意味着每个像素都是一个灰色阴影(即每个像素的 R、G 和 B 值都相同)。如果 R(或 G 或 B)值大于 128,我们将像素定义为按钮的一部分。
  2. 按钮边缘周围总会有几个像素(取决于阴影)比这更暗,因此不会算作按钮的一部分。这没关系。
  3. 我们需要知道如何“识别”一个按钮。基本上我们会寻找 R 值大于 128 的像素。但我们需要的不止这些——见下一节。
  4. 要在按钮周围绘制一个框,您需要知道按钮中所有像素的最小和最大 x 值以及所有像素的最小和最大 y 值。然后,该框的左上角为 (xmin, ymin),右下角为 (xmax, ymax),依此类推。
  5. 需要考虑如何定义“损坏”按钮。这完全取决于你。

Hints:损坏的按钮比未损坏的按钮具有更少的总像素。

Section C - the algorithm to identify a button in the image

一个按钮由 R 值大于 128 的像素组成,并且这些像素必须相互接触。 如果我们处理每个像素,我们可以通过以下方式识别按钮:
a) 找到一个 R 值大于 128 的像素
b) 找到连接到该像素的所有其他像素(并且 R 值大于 128)
c) 回到我们在 (a) 中的位置并继续
下面的图片试图展示这一点。
步骤 (a) 以黄色显示。 我们从左上角开始,在图像上下稳定工作,直到找到合适的像素。
步骤 (b) 以红色显示——我们找到所有像素连接到第一个像素。
步骤(c)显示为绿色——我们回到我们在步骤(a)的位置,继续寻找 R 值大于 128 的像素。注意这个图是为了得到这个想法——绘制并不完美。


现在让我们更详细地看一下步骤 (b)——如果按钮中有一个像素,我们如何找到其他像素?
假设我们在位置 (x, y) 发现像素 A 的 R 值大于 128。因此我们知道像素 A 在按钮内。 然后我们可以处理接触像素 A 的像素(它们是像素 B、C、D 和 E)。 注意这些像素的位置。 像素 B 与像素 A 位于图像的同一行,因此具有相同的 y 值。 但是像素 B 位于左侧一个位置,因此它的 x 值为 x – 1。像素 E 与像素 A 在图像的同一垂直列中,因此具有相同的 x 值。 但像素 E 位于屏幕下方,因此它的 y 值为 y + 1。其他像素也是如此。

现在我们知道如何识别像素 A 的“next door”像素,我们有一个算法如下:

  • 在位置 (x, y) 处找到像素 A 并通过以下方式查找所有连接的像素:
  • 在位置 (x – 1, y) 找到像素 B 并查找所有连接的像素;
  • 在位置 (x + 1, y) 处找到像素 C 并查找所有连接的像素;
  • 在位置 (x, y – 1) 处找到像素 D 并查找所有连接的像素;
  • 在位置 (x, y + 1) 处找到像素 E 并查找所有连接的像素;
    这是一个递归算法——通过找到连接到 B 的像素来找到连接到 A 的像素,等等。

虽然这可能看起来不像著名的“caves”plan,但本质上是相同的情况。我们有同样的问题。我们可以开发一个无限循环,其中像素 A 检查像素 B,检查像素 A,检查像素 B,等等。我们以相同的方式解决问题,即我们在每个像素中放入一个布尔值,一旦我们检查了一个像素我们将其从搜索中排除。不要再次检查该像素。

每个递归函数都需要一个基本情况。在这种情况下,有两个是:

  • 如果您正在检查的像素的 R 值等于或小于 128,则返回
  • 如果这个像素被排除在搜索之外(即如果这个像素之前已经被检查过),则返回

一些精明的读者可能已经注意到,我们将它们视为与像素 A 相邻的四个像素,而实际上有八个相邻的像素。我们省略了对角线像素。这样做的原因是递归最终会遍历所有相邻像素。例如。 A 上方和左侧的像素也在 B 上方,因此将在检查 B 时进行检查.

Section D

还有一个程序员曾经在工厂工作。 不幸的是,该程序员并未在清北学习 C++,因此无法完成该项目。 你可能会发现一些
部分完成的程序中有趣的想法,称为 Ass3-start.cpp
下载名为 Ass3-start.cpp 的程序并研究它。
您必须使用名为 pixel_class 的类。 请注意,其中两个方法位于程序的末尾。
这个类在注释中讨论过,但有一个名为 exclude 的额外布尔变量来辅助递归函数。 此排除变量在程序开始时设置为 false,如果已检查此特定像素,则设置为 true。
您必须使用以下全局变量:

int screenx, screeny, maxcolours;
pixel_class picture[600][600];

强烈建议您还使用全局变量:

int total, xmin, xmax, ymin, ymax; // these MUST be global

但是,如果您让程序在没有这些变量的情况下工作,那么您就不需要使用它们。

您必须完全按照程序中的方式使用名为 loadButtons 的函数。

剩下的就看你了。 只要您使用上面列出的强制性代码部分,您就可以保留程序中当前的所有内容或替换其中的一些内容。

主程序的基本概要如下:
• 使用函数loadButtons 将照片数据加载到图片中
• 通过所有像素识别按钮并将框放入图片中
• 将图片数据写入新的 .ppm 文件
•(在程序之外)将新的 .ppm 文件转换为 .bmp 并查看它
Extra notes on drawing a box:
您可以通过将特定颜色的像素放入图片中来绘制一个框(或实际上是任何东西)。
一个盒子需要四个值,分别是 xmin、xmax、ymin、ymax。
盒子的左上角是(xmin, ymin),盒子的右上角是(xmax, ymin)。
盒子的左下角是(xmin, ymax),盒子的右下角是(xmax, ymax)。
要绘制框的顶线,请使用以下循环(或类似循环):

for (x = xmin; x <= xmax; x++) {picture[x][ymin].loaddata(R, G, B);picture[x][ymin].setexclude(true);
}

将每个像素中的 exclude 变量设置为 true 非常重要。 这些像素现在是框的一部分,不再是按钮图像的一部分。 他们必须从任何未来的按钮搜索中排除。

Section E - output

程序的输出是存储在 .ppm 文件中的图像。 为了查看图像,您可能需要将其转换为不同的格式,例如 .bmp 文件。
输出图像必须显示按钮,每个按钮周围都显示框。 盒子必须是红色的
如果按钮损坏,如果按钮可以接受,则为绿色。 它应该是这样的:

然而,此图像仅显示绿色框。 这不是正确的结果。
Note1:如果您仔细观察,您可能会发现有些框并没有完美地位于按钮周围。 绿线的“反面”可能有一个或两个像素。 不要担心这个。 不要浪费数小时的时间试图让您的盒子比上面显示的更好。 这些框完全足以显示正在引用哪个按钮。
Note 2:您需要决定“损坏”按钮的定义。 有些按钮明显损坏,其他按钮可能没问题,对此不太确定。 欢迎来到现实世界中的编程! 只要明显损坏的按钮被归类为损坏,没关系。 可能有一两个按钮有些人可能认为已损坏,而其他人则可能不会。 在真实工厂中,“损坏”按钮在被丢弃之前由人类专家检查

Extra ideas

递归很难。

如果你发现很难弄清楚你需要做什么,那是完全正常的。

即使是最好的程序员通常也不会从头开始发明递归函数。

这里有一些关于如何处理任务 3的提示。

1.递归算法(和函数):
用于检查像素的递归算法如下所示:
在 location(x,y) 处找到像素 A 并通过以下方式查找所有连接的素:

  • 转到位置 (x–1,y) 处的像素 B 并查找所有连接的像素;
  • 转到位置 (x+1,y) 处的像素 C 并查找所有连接的像素;
  • 转到位置 (x,y-1) 处的像素 D 并查找所有连接的像素;
  • 转到位置 (x,y+1) 处的像素 E 并查找所有连接的像素;

并且这里有两个基本情况。
首先要注意 - 这是一个空函数。它做了一些事情,但它不返回任何值。参数应该
是 x 和 y(像素的位置)。
此算法的代码的基本方法是:

void findConnectedPixels(int x, int y) {if (picture[x][y].getexclude() == true{ return; }// base case oneif (picture[x][y].getR() <= 128) { return; }// base case two// use x and y to assist in calculating xmax, xmin, ymax, yminpicture[x][y].setexclude(true);// do not look at this pixel againfindConnectedPixels(x-1,y);findConnectedPixels(x,y-1);etc...
)

2.在按钮周围绘制一个框要绘制一个框
需要值 xmin、xmax、ymin、ymax。

这是递归函数的主要工作。

它会根据 x(或 y)检查 xmin(等)并根据需要进行调整。在 main 中初始化 xmin(等)——不要在函数内部初始化它们。在 main 中绘制框——不要在函数内部绘制框。

Answer

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;class pixel_class {private:int red, green, blue;bool exclude;  // do not check this pixel
public:void loaddata(int v1, int v2, int v3);void datatofile(fstream & ppmfile);int getR() { return red; }int getG() { return green; }int getB() { return blue; }void setexclude(bool ex) { exclude = ex; }bool getexclude() { return exclude; }
};void loadButtons();
void checkpixel(int x, int y);
void DrawBox(int R, int G, int B);int total, xmin, xmax, ymin, ymax;  // these MUST be globalint screenx, screeny, maxcolours;
pixel_class picture[600][600];int main() {int x, y, grey;string outfilename;fstream outfile;bool excluded;// Step 1 : read in the image from Buttons.ppmloadButtons();// Step 2 : draw a box around each buttonfor (y = 0; y < screeny; y++) {for (x = 0; x < screenx; x++) {grey = picture[x][y].getR();excluded = picture[x][y].getexclude();if ((grey > 128) && (excluded == false)) {total = 0;xmin = x;xmax = x;ymin = y;ymax = y;checkpixel(x, y);cout << "Total pixels = " << total << endl;if (total < 7700) {DrawBox(255, 0, 0);  // draw a red box} else {DrawBox(0, 255, 0);  // draw a green box}}}}// Step 3 : output the final .ppm fileoutfilename = "myImage.ppm";outfile.open(outfilename.c_str(), fstream::out);outfile << "P3\n";outfile << "# " << outfilename << endl;outfile << screenx << " " << screeny << endl;outfile << maxcolours << endl;for (y = 0; y < screeny; y++) {for (x = 0; x < screenx; x++) {picture[x][y].datatofile(outfile);}outfile << endl;}outfile.close();
}void loadButtons() {// load the picture from Buttons.ppmint x, y, R, G, B;fstream infile;string infilename, line;infilename = "Buttons.ppm";infile.open(infilename.c_str(), fstream::in);if (infile.is_open() == false) {cout << "ERROR: not able to open " << infilename << endl;exit(2);}getline(infile, line);  // this line is "P3"getline(infile, line);  // this line is "# filename"infile >> screenx >> screeny;  // this line is the sizeinfile >> maxcolours;  // this line is 256for (y = 0; y < screeny; y++) {for (x = 0; x < screenx; x++) {infile >> R >> G >> B;picture[x][y].loaddata(R, G, B);picture[x][y].setexclude(false);}}infile.close();
}void checkpixel(int x, int y) {// recursively check a pixel and its neighboursint grey;bool excluded;grey = picture[x][y].getR();if (grey <= 128) { return; }excluded = picture[x][y].getexclude();if (excluded == true) { return; }  // do not check thistotal++;           // add another pixelif (x < xmin) { xmin = x; }if (x > xmax) { xmax = x; }if (y < ymin) { ymin = y; }if (y > ymax) { ymax = y; }picture[x][y].setexclude(true);  // do not check againif (x > 0) { checkpixel(x - 1, y); }if (y > 0) { checkpixel(x, y - 1); }if (x < screenx - 1) { checkpixel(x + 1, y); }if (y < screeny - 1) { checkpixel(x, y + 1); }
}void DrawBox(int R, int G, int B) {// do not check the pixels of the box - use excludeint x, y;for (x = xmin; x <= xmax; x++) {picture[x][ymin].loaddata(R, G, B);picture[x][ymin].setexclude(true);picture[x][ymax].loaddata(R, G, B);picture[x][ymax].setexclude(true);}for (y = ymin; y <= ymax; y++) {picture[xmin][y].loaddata(R, G, B);picture[xmin][y].setexclude(true);picture[xmax][y].loaddata(R, G, B);picture[xmax][y].setexclude(true);}
}//--------------- methods for the pixel_class ------------
void pixel_class::loaddata(int v1, int v2, int v3) {red = v1;green = v2;blue = v3;
}void pixel_class::datatofile(fstream & ppmfile) {// write the data for one pixel to the ppm fileppmfile << red << " " << green;ppmfile << " " << blue << "  ";
}

C++程序设计(三:可视化)相关推荐

  1. MFC Windows 程序设计[三十五]之五彩十六宫格

    MFC Windows 程序设计[三十五]之五彩十六宫格 程序之美 前言 主体 运行效果 核心代码 逻辑分析 结束语 程序之美 前言 MFC是微软公司提供的一个类库(class libraries), ...

  2. MFC Windows 程序设计(三)-锦上添花(附源码)

    MFC Windows 程序设计(三)-锦上添花(附源码) 程序之美 所话说,爱美之心人皆有之,不管是对于男人,女人,还是小孩,都有对美的一种向往,美好的事物,给人一种动力,一种希望,一种期盼,一种留 ...

  3. Scanpy(三)可视化函数

    目录 Scatter plots for embeddings(embedding的散点图) 基于marker基因的簇识别 Combining plots in subplots使用子图 Heatma ...

  4. C++程序设计三周教学记录

    从第五周到第八周,除去第七周的国庆,C++共上了三周的课.大一新生三周能学会些什么?他们已经能输出漂亮的星号图了.身为老师的我,和这群大孩子一样高兴.同学们的努力令我感动,自己的不少非常规的想法和做法 ...

  5. 【ARM】ARM汇编程序设计(三) 循环结构

    00. 目录 文章目录 00. 目录 01. 循环结构-死循环 02. 循环结构-累加和 03. 循环结构-循环输出 04. 循环结构-循环输出 05. 随机数 06. 综合应用一 07. 综合应用二 ...

  6. [Oracle]高效的PL/SQL程序设计(三)--Package的优点

    使用Package的优点在于提供了必需的程序设计结构, 促进了模块化编程设计, 最重要的是Package断开了依赖链, 使得对某个数据库模式的改动不会导致整个模式的无效,从而避免了昂贵的重编译! 例如 ...

  7. 算法与程序设计(三):动态规划算法

    目录 一.概念 1.1 动态规划算法的基本要素 1.2 动态规划算法的步骤 二.举例 2.1 矩阵连乘问题 2.1.1 穷举法 2.1.2 动态规划法 2.1.3 例题 2.2 图像压缩问题 2.3 ...

  8. python程序设计论文_【程序设计论文】程序设计论文范文(共40篇)

    发表于:2020/10/20 11:53:15 点击数:77次 微信小程序开发课程改革实践 [摘要]微信小程序由于具有不同于传统移动APP的诸多优点,自推出以来得到了业界的广泛关注,计算机类专业人才培 ...

  9. c语言循环结构程序设计视频,第13讲:循环结构程序设计1

    C语言是计算机科学及应用专业的一门重要的专业基础 课,也是全校各 个专业的公共必修课程.它既可以为其它专业课程奠定程序设计的基础,又可以作为其它专业课程的程序设计的工具. 通过本课程的学习,应掌握计算 ...

  10. 一款 0 门槛轻松易上手的数据可视化工具

    在职场中有一项共识是:数据驱动业务价值.业务在产品.运营.开发.技术支持.销售等环节都有着大量的数据需求, 市面上也出现了很多 BI 可视化工具,但如果能同时具备以下特性,则可以称为一款优秀的 BI ...

最新文章

  1. [转]【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现
  2. Android几秒后自动关闭dialog
  3. 【计算机系统设计】重点 · 学习笔记(0)(数据通路设计思想)
  4. Intel Hyperscan简介
  5. android最新v7包下载,support v7 appcompat.jar包下载
  6. js中运算符的优先级
  7. 【xposed】虚拟机安装Magisk和LSPoesd
  8. Unity2017 经典游戏开发教程 算法分析与实现 (张帆 著)
  9. 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法
  10. 无人船水下地形测量的应用及优势
  11. 你应该学点哲学的20个理由:不为拥有深奥的思想,只为更好地生活
  12. 初识中央处理器CPU
  13. Android 5.X 新特性详解(一)MD主题、Palette、视图阴影、Tinting(着色)和Clipping(裁剪)
  14. gif动态图gif出处_我喜欢GIF的怪异事物
  15. 13.“二四六分明”与特定变格
  16. html5经纬度定位 源码_基于浏览器的HTML5地理定位
  17. 使用CSS网格布局放置元素的七种方法
  18. 我哭了——学分不保篇——注意——开学才一个月——啊这能学?——完犊子
  19. QQ引流怎么搞?怎么用QQ来引流?QQ引流的技巧
  20. Python爬虫从入门到精通:(43)JS逆向:完美世界RAS逆向_Python涛哥

热门文章

  1. PyTorch学习—13.优化器optimizer的概念及常用优化器
  2. python—符号 | ^的使用
  3. python—IFrame:在jupyter notebook中展示某个网页的情况
  4. 利用python进行数据分析—9.数据规整:连接、联合与重塑
  5. python——extend用新序列扩展其他列表
  6. Datawhale编程学习之图(6)
  7. 吴恩达深度学习——目标检测
  8. 杨强教授领衔撰写,国内首本联邦学习实战的权威著作
  9. 读取csv文件中的IMU数据并以sensor_msgs/Imu格式发送
  10. 7-3 时间换算 (15 分)