windows C++-创建图像处理的异步消息(二)

 创建图像处理网络

此部分介绍如何创建对给定目录中的每个 JPEG (.jpg) 图像执行图像处理的异步消息块网络。 网络执行以下图像处理操作:

  1. 对于 Tom 创作的任何图像,转换为灰度。

  2. 对于任何以红色作为主色的图像,移除绿色和蓝色分量,然后将其变暗。

  3. 对于任何其他图像,应用棕色调。

网络仅应用与其中一个条件匹配的第一个图像处理操作。 例如,如果图像由 Tom 创作,并且将红色作为其主色,则图像仅转换为灰度。

网络执行每个图像处理操作后,它会将图像作为位图 (.bmp) 文件保存到磁盘。

以下步骤演示如何创建实现此图像处理网络的函数,并将该网络应用于给定目录中的每个 JPEG 图像。

创建图像处理网络

// 1. 创建函数 ProcessImages,它会采用磁盘上某个目录的名称。

void ProcessImages(const wstring& directory)
{
}

// 2. 在 ProcessImages 函数中,创建 countdown_event 变量。 本演练稍后会对 countdown_event 类进行介绍。
// Holds the number of active image processing operations and 
// signals to the main thread that processing is complete.
countdown_event active(0);

// 3. 创建将 Bitmap 对象与其原始文件名关联的 std::map 对象。
// Maps Bitmap objects to their original file names.
map<Bitmap*, wstring> bitmap_file_names;

// 4. 添加以下代码以定义图像处理网络的成员。
 //
 // Create the nodes of the network.
 //

 // Loads Bitmap objects from disk.
 transformer<wstring, Bitmap*> load_bitmap(
    [&](wstring file_name) -> Bitmap* {
       Bitmap* bmp = new Bitmap(file_name.c_str());
       if (bmp != nullptr)
          bitmap_file_names.insert(make_pair(bmp, file_name));
       return bmp;
    }
 );

 // Holds loaded Bitmap objects.
 unbounded_buffer<Bitmap*> loaded_bitmaps;

 // Converts images that are authored by Tom to grayscale.
 transformer<Bitmap*, Bitmap*> grayscale(
    [](Bitmap* bmp) {
       return Grayscale(bmp);
    },
    nullptr,
    [](Bitmap* bmp) -> bool {
       if (bmp == nullptr)
          return false;

       // Retrieve the artist name from metadata.
       UINT size = bmp->GetPropertyItemSize(PropertyTagArtist);
       if (size == 0)
          // Image does not have the Artist property.
          return false;

       PropertyItem* artistProperty = (PropertyItem*) malloc(size);
       bmp->GetPropertyItem(PropertyTagArtist, size, artistProperty);
       string artist(reinterpret_cast<char*>(artistProperty->value));
       free(artistProperty);
       
       return (artist.find("Tom ") == 0);
    }
 );
 
 // Removes the green and blue color components from images that have red as
 // their dominant color.
 transformer<Bitmap*, Bitmap*> colormask(
    [](Bitmap* bmp) {
       return ColorMask(bmp, 0x00ff0000);
    },
    nullptr,
    [](Bitmap* bmp) -> bool { 
       if (bmp == nullptr)
          return false;
       return (GetColorDominance(bmp) == 0x00ff0000);
    }
 );

 // Darkens the color of the provided Bitmap object.
 transformer<Bitmap*, Bitmap*> darken([](Bitmap* bmp) {
    return Darken(bmp, 50);
 });

 // Applies sepia toning to the remaining images.
 transformer<Bitmap*, Bitmap*> sepiatone(
    [](Bitmap* bmp) {
       return Sepiatone(bmp);
    },
    nullptr,
    [](Bitmap* bmp) -> bool { return bmp != nullptr; }
 );

 // Saves Bitmap objects to disk.
 transformer<Bitmap*, Bitmap*> save_bitmap([&](Bitmap* bmp) -> Bitmap* {
    // Replace the file extension with .bmp.
    wstring file_name = bitmap_file_names[bmp];
    file_name.replace(file_name.rfind(L'.') + 1, 3, L"bmp");
    
    // Save the processed image.
    CLSID bmpClsid;
    GetEncoderClsid(L"image/bmp", &bmpClsid);      
    bmp->Save(file_name.c_str(), &bmpClsid);

    return bmp;
 });

 // Deletes Bitmap objects.
 transformer<Bitmap*, Bitmap*> delete_bitmap([](Bitmap* bmp) -> Bitmap* {      
    delete bmp;
    return nullptr;
 });

 // Decrements the event counter.
 call<Bitmap*> decrement([&](Bitmap* _) {      
    active.signal();
 });

// 5. 添加以下代码以连接网络。
//
// Connect the network.
//   

load_bitmap.link_target(&loaded_bitmaps);

loaded_bitmaps.link_target(&grayscale);
loaded_bitmaps.link_target(&colormask);   
colormask.link_target(&darken);
loaded_bitmaps.link_target(&sepiatone);
loaded_bitmaps.link_target(&decrement);

grayscale.link_target(&save_bitmap);
darken.link_target(&save_bitmap);
sepiatone.link_target(&save_bitmap);

save_bitmap.link_target(&delete_bitmap);
delete_bitmap.link_target(&decrement);

// 6. 添加以下代码以向网络头发送目录中每个 JPEG 文件的完整路径。

// Traverse all files in the directory.
wstring searchPattern = directory;
searchPattern.append(L"\\*");

WIN32_FIND_DATA fileFindData;
HANDLE hFind = FindFirstFile(searchPattern.c_str(), &fileFindData);
if (hFind == INVALID_HANDLE_VALUE) 
   return;
do
{
   if (!(fileFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
   {
      wstring file = fileFindData.cFileName;

      // Process only JPEG files.
      if (file.rfind(L".jpg") == file.length() - 4)
      {
         // Form the full path to the file.
         wstring full_path(directory);
         full_path.append(L"\\");
         full_path.append(file);

         // Increment the count of work items.
         active.add_count();

         // Send the path name to the network.
         send(load_bitmap, full_path);
      }
   }
}
while (FindNextFile(hFind, &fileFindData) != 0); 
FindClose(hFind);

// 7. 等待 countdown_event 变量达到零。
// Wait for all operations to finish.
active.wait();

图像网络成员

下表描述了网络的成员:

a06aca143e494df2bb35be9e5942b61b.png

loaded_bitmaps 消息缓冲区非常重要,因为作为 unbounded_buffer 对象,它可向多个接收方提供 Bitmap 对象。 当目标块接受 Bitmap 对象时,unbounded_buffer 对象不会向任何其他目标提供该 Bitmap 对象。 因此,将对象链接到 unbounded_buffer 对象的顺序非常重要。 grayscale、colormask 和 sepiatone 消息块各自都使用筛选器,以便仅接受特定 Bitmap 对象。 decrement 消息缓冲区是 loaded_bitmaps 消息缓冲区的重要目标,因为它接受其他消息缓冲区所拒绝的所有 Bitmap 对象。 需要 unbounded_buffer 对象以便按顺序传播消息。 因此,unbounded_buffer 对象会在新目标块链接到它之前阻塞,并在没有当前目标块接受该消息时接受消息。

如果应用程序需要多个消息块处理消息,而不只是第一个接受消息的消息块,则可以使用另一种消息块类型,例如 overwrite_buffer。 overwrite_buffer 类一次保存一个消息,但它会将该消息传播到其每个目标。

下表描述了网络的成员。

5ec818868ef048919c5af660a3d9c464.png

此示例中的 countdown_event 对象使图像处理网络能够在处理了所有图像后告知主应用程序。 countdown_event 类使用 concurrency::event 对象在计数器值达到零时发送信号。 主应用程序在每次将文件名发送到网络时使计数器递增。 网络终端节点在处理每个图像后使计数器递减。 在主应用程序遍历指定目录后,它会等待 countdown_event 对象发出指示其计数器已达到零的信号。

下面的示例展示了 countdown_event 类:

// A synchronization primitive that is signaled when its 
// count reaches zero.
class countdown_event
{
public:
   countdown_event(unsigned int count = 0)
      : _current(static_cast<long>(count)) 
   {
      // Set the event if the initial count is zero.
      if (_current == 0L)
         _event.set();
   }
     
   // Decrements the event counter.
   void signal() {
      if(InterlockedDecrement(&_current) == 0L) {
         _event.set();
      }
   }

   // Increments the event counter.
   void add_count() {
      if(InterlockedIncrement(&_current) == 1L) {
         _event.reset();
      }
   }
   
   // Blocks the current context until the event is set.
   void wait() {
      _event.wait();
   }
 
private:
   // The current count.
   volatile long _current;
   // The event that is set when the counter reaches zero.
   event _event;

   // Disable copy constructor.
   countdown_event(const countdown_event&);
   // Disable assignment.
   countdown_event const & operator=(countdown_event const&);
};

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提升开机速度:有效管理Windows电脑自启动项,打开、关闭自启动项教程分享

日常使用Windows电脑时&#xff0c;总会需要下载各种各样的办公软件。部分软件会默认开机自启功能&#xff0c;开机启动项是指那些在电脑启动时自动运行的程序和服务。电脑开机自启太多的情况下会导致电脑卡顿&#xff0c;开机慢&#xff0c;运行不流畅的情况出现&#xff0c;而…

Unity各个操作功能+基本游戏物体创建与编辑+Unity场景概念及文件导入导出

各个操作功能 部分功能 几种操作游戏物体的方式&#xff1a; Center:有游戏物体父子关系的时候&#xff0c;中心点位置 Global/Local:世界坐标系方向/自身坐标系方向 &#xff1a;调试/暂停/下一帧 快捷键 1.Alt鼠标左键&#xff1a;可以实现巡游角度查看场景 2.鼠标滚轮…

mysql join的使用

MySQL 支持以下 JOIN 语法用于 SELECT 语句和多表 DELETE 和 UPDATE 语句中的 table_references 部分&#xff1a; table_references: 查询中涉及的一个或多个表的引用&#xff0c;可以是简单表名或 JOIN 表达式的组合。 escaped_table_reference [, escaped_table_referenc…

10.7学习

1.安全认证 ●Session 认证中最常用的一种方式&#xff0c;也是最简单的。存在多节点session丢失的情况&#xff0c;可通过nginx粘性Cookie和Redis集中式Session存储解决 ●HTTP Basic Authentication 服务端针对请求头中base64加密的Authorization 和用户名和密码进行校验。…

《贪吃蛇小游戏 1.0》源码

好久不见&#xff01; 终于搞好了简易版贪吃蛇小游戏&#xff08;C语言版&#xff09;&#xff0c;邀请你来玩一下~ 目录 Snake.h Snake.c test.c Snake.h #include<stdio.h> #include<windows.h> #include<stdbool.h> #include<stdlib.h> #inclu…

Ascend C 自定义算子开发:高效的算子实现

Ascend C 自定义算子开发&#xff1a;高效的算子实现 在 Ascend C 平台上&#xff0c;开发自定义算子能够充分发挥硬件的性能优势&#xff0c;帮助开发者针对不同的应用场景进行优化。本文将以 AddCustom 算子为例&#xff0c;介绍 Ascend C 中自定义算子的开发流程及关键技术…

FireRedTTS - 小红书最新开源AI语音克隆合成系统 免训练一键音频克隆 本地一键整合包下载

小红书技术团队FireRed最近推出了一款名为FireRedTTS的先进语音合成系统&#xff0c;该系统能够基于少量参考音频快速模仿任意音色和说话风格&#xff0c;实现独特的音频内容创造。 FireRedTTS 只需要给定文本和几秒钟参考音频&#xff0c;无需训练&#xff0c;就可模仿任意音色…

[记录]-安装pycharm

官网下载安装包&#xff1a;https://www.jetbrains.com/pycharm/ 然后按照引导安装 全部勾选

【数据管理】DAMA-元数据专题

导读&#xff1a;元数据是关于数据的组织、数据域及其关系的信息&#xff0c;是描述数据的数据。在数据治理中&#xff0c;元数据扮演着至关重要的角色&#xff0c;是数据治理的基础和支撑。以下是对数据治理中元数据专题方案的详细介绍&#xff1a; 目录 一、元数据的重要性 …

VRRP协议个人理解+报文示例+典型配置-RFC2338/RFC3768/RFC5798/RFC9568

个人认为&#xff0c;理解报文就理解了协议。通过报文中的字段可以理解协议在交互过程中相关传递的信息&#xff0c;更加便于理解协议。 因此本文将在VRRP协议报文的基础上进行介绍。 VRRP协议发展 关于VRRPv2基本原理&#xff0c;可重点参考2004年发布的RFC3768-Virtual Ro…

【Python|接口自动化测试】使用requests发送http请求时添加headers

文章目录 1.前言2.HTTP请求头的作用3.在不添加headers时4.反爬虫是什么&#xff1f;5.在请求时添加headers 1.前言 本篇文章主要讲解如何使用requests请求时添加headers&#xff0c;为什么要加headers呢&#xff1f;是因为有些接口不添加headers时&#xff0c;请求会失败。 2…

【C++ Primer Plus】4

2 字符串 字符串是存储在内存的连续字节中的一系列字符&#xff1b;C处理字符串的方式有两种&#xff0c; c-风格字符串&#xff08;C-Style string&#xff09;string 类 2.1 c-风格字符串&#xff08;C-Style string&#xff09; 2.1.1 char数组存储字符串&#xff08;c-…

Python编码规范与常见问题纠正

Python编码规范与常见问题纠正 Python 是一种以简洁和易读性著称的编程语言&#xff0c;因此&#xff0c;遵循良好的编码规范不仅能使代码易于维护&#xff0c;还能提升代码的可读性和可扩展性。编写规范的 Python 代码也是开发者职业素养的一部分&#xff0c;本文将从 Python…

Linux聊天集群开发之环境准备

一.windows下远程操作Linux 第一步&#xff1a;在Linux终端下配置openssh&#xff0c;输入netstate -tanp,查看ssh服务是否启动&#xff0c;默认端口22.。 注&#xff1a;如果openssh服务&#xff0c;则需下载。输入命令ps -e|grep ssh, 查看如否配有&#xff0c; ssh-agent …

tensorflow快速入门--如何定义张量、定义网络结构、超参数设置、模型训练???

前言 由于最近学习的东西涉及到tensorflow的使用&#xff0c;故先简单的学习了一下tensorflow中如何定义张量、定义网络结构、超参数设置、模型训练的API调用过程&#xff1b;欢迎大家&#xff0c;收藏关注&#xff0c;本人将持续更新。 文章目录 1、基本操作1、张量基础操作创…

[Python] 编程入门:理解变量类型

文章目录 [toc] 整数常见操作 浮点数字符串字符串中混用引号问题字符串长度计算字符串拼接 布尔类型动态类型特性类型转换结语 收录专栏&#xff1a;[Python] 在编程中&#xff0c;变量是用于存储数据的容器&#xff0c;而不同的变量类型则用来存储不同种类的数据。Python 与 C…

爬虫——爬虫理论+request模块

一、爬虫理论 爬虫——请求网站并提取数据的自动化程序 网络爬虫&#xff08;又被称为网页蜘蛛&#xff0c;网络机器人&#xff09;就是模拟客户端发送网络请求&#xff0c;接收请求响应&#xff0c;一种按照一定的规则&#xff0c;自动的抓取互联网信息的程序。 原则上&…

SQL第12课——联结表

三点&#xff1a;什么是联结&#xff1f;为什么使用联结&#xff1f;如何编写使用联结的select语句 12.1 联结 SQL最强大的功能之一就是能在数据查询的执行中联结&#xff08;join)表。联结是利用SQL的select能执行的最重要的操作。 在使用联结前&#xff0c;需要了解关系表…

【数据结构 | PTA】栈

文章目录 7-1 汉诺塔的非递归实现7-2 出栈序列的合法性**7-3 简单计算器**7-4 盲盒包装流水线 7-1 汉诺塔的非递归实现 借助堆栈以非递归&#xff08;循环&#xff09;方式求解汉诺塔的问题&#xff08;n, a, b, c&#xff09;&#xff0c;即将N个盘子从起始柱&#xff08;标记…

Golang | Leetcode Golang题解之第447题回旋镖的数量

题目&#xff1a; 题解&#xff1a; func numberOfBoomerangs(points [][]int) (ans int) {for _, p : range points {cnt : map[int]int{}for _, q : range points {dis : (p[0]-q[0])*(p[0]-q[0]) (p[1]-q[1])*(p[1]-q[1])cnt[dis]}for _, m : range cnt {ans m * (m - 1)…