İzlenecek yol: görüntü işleme ağ oluşturma
Bu belge Görüntü işlemeyi gerçekleştirmek, zaman uyumsuz ileti blokları ağının oluşturulması gösterilmiştir.
Ağ karakteristiklerini dayanılarak bir görüntü üzerinde gerçekleştirmek için hangi işlemleri belirler. Bu örnek dataflow ağ üzerinden yol görüntüleri model. Dataflow modelinde bir programın bağımsız bileşenler iletileri göndererek birbirleriyle. Bir bileşen, bir ileti aldığında, onu bazı eylemleri gerçekleştirmek ve sonra başka bir bileşen için o eylemi sonucu geçmesi. Bu karşılaştırma akış denetimi modeli, bir uygulamanın kullandığı denetim yapıları, örneğin, koşullu deyimleri, döngüler ve benzeri bir programda işlemlerin sırasını denetlemek için.
Dataflow üzerinde ağ oluşturur bir Potansiyel görevler. Ardışık her aşamasında aynı anda genel görev bölümünü yapar. Bu benzetme, otomobil üretim için derleme çizgidir. Her araç montaj hattı üzerinden geçerken bir istasyon çerçeve birleştirir, başka alt yapısı ve benzeri yükler. Aynı anda derlenip birden fazla taşıtlar etkinleştirerek, montaj hattı tam taşıtlar bir anda montajı çok daha iyi üretilen iş sağlar.
Önkoşullar
Bu izlenecek yolda, başlamadan önce aşağıdaki belgeleri okuyun:
Temellerini anlamak da öneririz GDI+ bu yönergeyi başlamadan önce. Hakkında daha fazla bilgi için GDI+, bakın GDI +.
Bölümler
Bu izlenecek yolda, aşağıdaki bölümleri içerir:
Görüntü işleme işlevselliği tanımlama
Görüntü işleme ağ oluşturma
Örneğin
Görüntü işleme işlevselliği tanımlama
Bu bölümde, görüntü işleme ağ diskten okunan resimlerle çalışmak için kullandığı destek işlevlerini gösterir.
Aşağıdaki işlevler, GetRGB ve MakeColor, ayıklamak ve sırasıyla verilen renk tek tek bileşenlerini birleştirebilirsiniz.
// Retrieves the red, green, and blue components from the given
// color value.
void GetRGB(DWORD color, BYTE& r, BYTE& g, BYTE& b)
{
r = static_cast<BYTE>((color & 0x00ff0000) >> 16);
g = static_cast<BYTE>((color & 0x0000ff00) >> 8);
b = static_cast<BYTE>((color & 0x000000ff));
}
// Creates a single color value from the provided red, green,
// and blue components.
DWORD MakeColor(BYTE r, BYTE g, BYTE b)
{
return (r<<16) | (g<<8) | (b);
}
Aşağıdaki işlev ProcessImage, çağrı verilen std::function her bir pikselin renk değeri dönüştürmek için nesne bir GDI+Bitmap nesnesi. ProcessImage İşlevini kullanan concurrency::parallel_for her satır bitmap paralel işleme algoritması.
// Calls the provided function for each pixel in a Bitmap object.
void ProcessImage(Bitmap* bmp, const function<void (DWORD&)>& f)
{
int width = bmp->GetWidth();
int height = bmp->GetHeight();
// Lock the bitmap.
BitmapData bitmapData;
Rect rect(0, 0, bmp->GetWidth(), bmp->GetHeight());
bmp->LockBits(&rect, ImageLockModeWrite, PixelFormat32bppRGB, &bitmapData);
// Get a pointer to the bitmap data.
DWORD* image_bits = (DWORD*)bitmapData.Scan0;
// Call the function for each pixel in the image.
parallel_for (0, height, [&, width](int y)
{
for (int x = 0; x < width; ++x)
{
// Get the current pixel value.
DWORD* curr_pixel = image_bits + (y * width) + x;
// Call the function.
f(*curr_pixel);
}
});
// Unlock the bitmap.
bmp->UnlockBits(&bitmapData);
}
Aşağıdaki işlevler, Grayscale, Sepiatone, ColorMask, ve Darken, çağrı ProcessImage işlevi, her bir pikselin renk değeri dönüştürmek için bir Bitmap nesnesi. Lambda ifadesi Bu işlevlerden her biri bir pikselin renk dönüştürme tanımlamak için kullanır.
// Converts the given image to grayscale.
Bitmap* Grayscale(Bitmap* bmp)
{
ProcessImage(bmp,
[](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
// Set each color component to the average of
// the original components.
BYTE c = (static_cast<WORD>(r) + g + b) / 3;
color = MakeColor(c, c, c);
}
);
return bmp;
}
// Applies sepia toning to the provided image.
Bitmap* Sepiatone(Bitmap* bmp)
{
ProcessImage(bmp,
[](DWORD& color) {
BYTE r0, g0, b0;
GetRGB(color, r0, g0, b0);
WORD r1 = static_cast<WORD>((r0 * .393) + (g0 *.769) + (b0 * .189));
WORD g1 = static_cast<WORD>((r0 * .349) + (g0 *.686) + (b0 * .168));
WORD b1 = static_cast<WORD>((r0 * .272) + (g0 *.534) + (b0 * .131));
color = MakeColor(min(0xff, r1), min(0xff, g1), min(0xff, b1));
}
);
return bmp;
}
// Applies the given color mask to each pixel in the provided image.
Bitmap* ColorMask(Bitmap* bmp, DWORD mask)
{
ProcessImage(bmp,
[mask](DWORD& color) {
color = color & mask;
}
);
return bmp;
}
// Darkens the provided image by the given amount.
Bitmap* Darken(Bitmap* bmp, unsigned int percent)
{
if (percent > 100)
throw invalid_argument("Darken: percent must less than 100.");
double factor = percent / 100.0;
ProcessImage(bmp,
[factor](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
r = static_cast<BYTE>(factor*r);
g = static_cast<BYTE>(factor*g);
b = static_cast<BYTE>(factor*b);
color = MakeColor(r, g, b);
}
);
return bmp;
}
Aşağıdaki işlev, GetColorDominance, ayrıca çağrı ProcessImage işlevi. Ancak, her renk değerinin değiştirilmesi yerine bu işlevi kullanır concurrency::combinable kırmızı, yeşil veya mavi renk bileşeni görüntü dominates olup olmadığını hesaplamak için nesneler.
// Determines which color component (red, green, or blue) is most dominant
// in the given image and returns a corresponding color mask.
DWORD GetColorDominance(Bitmap* bmp)
{
// The ProcessImage function processes the image in parallel.
// The following combinable objects enable the callback function
// to increment the color counts without using a lock.
combinable<unsigned int> reds;
combinable<unsigned int> greens;
combinable<unsigned int> blues;
ProcessImage(bmp,
[&](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
if (r >= g && r >= b)
reds.local()++;
else if (g >= r && g >= b)
greens.local()++;
else
blues.local()++;
}
);
// Determine which color is dominant and return the corresponding
// color mask.
unsigned int r = reds.combine(plus<unsigned int>());
unsigned int g = greens.combine(plus<unsigned int>());
unsigned int b = blues.combine(plus<unsigned int>());
if (r + r >= g + b)
return 0x00ff0000;
else if (g + g >= r + b)
return 0x0000ff00;
else
return 0x000000ff;
}
Aşağıdaki işlev, GetEncoderClsid, bir kodlayıcı verilen MIME türü için sınıf tanımlayıcısı alır. Uygulama, bir bit eşlem Kodlayıcıdan almak için bu işlevi kullanır.
// Retrieves the class identifier for the given MIME type of an encoder.
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = nullptr;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == nullptr)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}
Top
Görüntü işleme ağ oluşturma
Bu bölümde ağ üzerinde Görüntü işlemeyi gerçekleştirmek, zaman uyumsuz ileti bloklarının nasıl açıklar her JPEG belirli bir dizinde bulunan resim (.jpg). Ağ görüntü işleme aşağıdaki işlemleri gerçekleştirir:
Tom tarafından yazılmış herhangi bir görüntüyü gri tonlamaya dönüştürün.
Baskın rengi kırmızı olan herhangi bir görüntü için yeşil ve mavi bileşenleri kaldırmak ve bunu koyulaştırmak.
Sepya tonlama başka herhangi bir görüntü için geçerlidir.
Ağ, bu durumlardan biriyle eşleşen yalnızca ilk görüntü işleme işlemi uygulanır. Örneğin, görüntüyü Tom tarafından yazılan ve baskın rengi kırmızı, görüntünün yalnızca gri tonlamaya dönüştürülür.
Ağ her görüntü işleme işlemi gerçekleştirdikten sonra bir bit eşlem (.bmp) dosyası olarak diske görüntü kaydeder.
Nasıl bu görüntü işleme ağ uygular ve bu ağın geçerli bir işlev oluşturmak aşağıdaki adımları göstermek için her JPEG belirli bir dizinde bulunan görüntü.
Görüntü işleme ağ oluşturmak için
Bir işlev oluşturun ProcessImages, disk üzerinde bir dizinin adını alır.
void ProcessImages(const wstring& directory) { }
De ProcessImages işlev, oluşturma bir countdown_event değişkeni. countdown_event Sınıfı Bu izlenecek yolda gösterilen.
// Holds the number of active image processing operations and // signals to the main thread that processing is complete. countdown_event active(0);
Oluşturma bir std::map associates nesnesi bir Bitmap nesnenin özgün dosya adına sahip.
// Maps Bitmap objects to their original file names. map<Bitmap*, wstring> bitmap_file_names;
Görüntü işleme ağ üyelerini tanımlamak için şu kodu ekleyin.
// // 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(); });
Ağa bağlanmak için aşağıdaki kodu ekleyin.
// // 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);
Ağ kafa için tam yolu her göndermek için aşağıdaki kodu ekleyip JPEG dizininde dosya.
// 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);
Bekle countdown_event sıfır ulaşmak için değişken.
// Wait for all operations to finish. active.wait();
Aşağıdaki tabloda ağ üyeleri açıklanmaktadır.
Üye |
Description |
---|---|
load_bitmap |
A concurrency::transformer yükler nesnesi bir Bitmap nesne diskten ve bir girdi ekler map görüntüyü orijinal dosya adıyla ilişkilendirilecek nesnesi. |
loaded_bitmaps |
A concurrency::unbounded_buffer yüklenen resimler resim işleme filtreleri gönderir nesnesi. |
grayscale |
A transformer gri tonlamaya Tom tarafından yazılmış olan resimleri dönüştürür Nesne. Görüntünün meta verileri, yazarı belirlemek için kullanır. |
colormask |
A transformer baskın rengi kırmızı olan görüntüleri yeşil ve mavi renk bileşenlerini kaldırır nesnesi. |
darken |
A transformer baskın rengi kırmızı olan görüntüleri koyulaştırır nesnesi. |
sepiatone |
A transformer Tom tarafından yazılmaz ve büyük kısmında kırmızı değil görüntüleri sararmış tonlama uygulanan nesnesi. |
save_bitmap |
A transformer işlenen kaydeder nesne image bir bitmap olarak diske. save_bitmaporijinal dosya adını alır map nesne ve dosya adı uzantısı .bmp için değiştirir. |
delete_bitmap |
A transformer görüntüleri için belleği boşaltır nesnesi. |
decrement |
A concurrency::call ağdaki terminal düğüm görevi gören bir nesne. Onu azaltır countdown_event görüntüyü işlenen ana uygulama sinyal nesnesi. |
loaded_bitmaps İleti arabelleği önemlidir çünkü olarak bir unbounded_buffer sunduğu nesne Bitmap alınmasından nesneler. Ne zaman bir hedef blok kabul bir Bitmap nesnesi, unbounded_buffer nesnesini sunmaz, Bitmap diğer hedefler için nesne. Hangi bağlantı sırası bu nedenle, nesne bir unbounded_buffer nesne önemlidir. grayscale, colormask, Ve sepiatone ileti blokları her kabul etmek için bir filtre kullanmak yalnızca belirli Bitmap nesneler. decrement İleti arabelleği önemli bir hedefi olan loaded_bitmaps tüm kabul iletisi arabellek Bitmap ileti arabellekleri tarafından reddedilen nesneler. Bir unbounded_buffer nesne sırayla iletiler yaymak için gereklidir. Bu nedenle, bir unbounded_buffer nesne yeni bir hedef blok bağlı olduğu ve geçerli bir hedef blok ileti kabul ederse, ileti kabul kadar engeller.
Birden çok ileti işlem yalnızca ilk ileti kabul eden bir ileti bloğu yerine iletiyi engeller uygulamanız gerektiriyorsa, başka bir ileti bloğu türü gibi kullanabilirsiniz overwrite_buffer. overwrite_buffer Sınıf aynı anda tek bir ileti içerir, ancak bu iletiyi her hedeflerine yayar.
Görüntü işleme ağ aşağıda gösterilmiştir:
countdown_event Nesne bu örnekte tüm görüntüleri işlendiğinde, ana uygulama bilgilendirmek görüntü işleme ağ sağlar. countdown_event Sınıfını kullanan bir concurrency::event nesnesine sayaç değeri sıfır olduğunda sinyal. Bu BT dosya adı ağa her ana uygulama sayacı artırır. Terminal düğüm ağ azaltır, her görüntüyü işlendikten sonra sayaç. Ana uygulama belirtilen dizine erişir sonra için bekler countdown_event nesne, sayaç sıfıra ulaştı sinyal.
Aşağıdaki örnekte gösterildiği countdown_event sınıfı:
// 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&);
};
Top
Örneğin
Örneğin aşağıdaki kodu gösterilir. wmain İşlevi yönetir GDI+ kitaplığı ve aramalar ProcessImages işlev için işlem JPEG dosyalar Örnek resimler dizin.
// image-processing-network.cpp
// compile with: /DUNICODE /EHsc image-processing-network.cpp /link gdiplus.lib
#include <windows.h>
#include <gdiplus.h>
#include <iostream>
#include <map>
#include <agents.h>
#include <ppl.h>
using namespace concurrency;
using namespace Gdiplus;
using namespace std;
// Retrieves the red, green, and blue components from the given
// color value.
void GetRGB(DWORD color, BYTE& r, BYTE& g, BYTE& b)
{
r = static_cast<BYTE>((color & 0x00ff0000) >> 16);
g = static_cast<BYTE>((color & 0x0000ff00) >> 8);
b = static_cast<BYTE>((color & 0x000000ff));
}
// Creates a single color value from the provided red, green,
// and blue components.
DWORD MakeColor(BYTE r, BYTE g, BYTE b)
{
return (r<<16) | (g<<8) | (b);
}
// Calls the provided function for each pixel in a Bitmap object.
void ProcessImage(Bitmap* bmp, const function<void (DWORD&)>& f)
{
int width = bmp->GetWidth();
int height = bmp->GetHeight();
// Lock the bitmap.
BitmapData bitmapData;
Rect rect(0, 0, bmp->GetWidth(), bmp->GetHeight());
bmp->LockBits(&rect, ImageLockModeWrite, PixelFormat32bppRGB, &bitmapData);
// Get a pointer to the bitmap data.
DWORD* image_bits = (DWORD*)bitmapData.Scan0;
// Call the function for each pixel in the image.
parallel_for (0, height, [&, width](int y)
{
for (int x = 0; x < width; ++x)
{
// Get the current pixel value.
DWORD* curr_pixel = image_bits + (y * width) + x;
// Call the function.
f(*curr_pixel);
}
});
// Unlock the bitmap.
bmp->UnlockBits(&bitmapData);
}
// Converts the given image to grayscale.
Bitmap* Grayscale(Bitmap* bmp)
{
ProcessImage(bmp,
[](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
// Set each color component to the average of
// the original components.
BYTE c = (static_cast<WORD>(r) + g + b) / 3;
color = MakeColor(c, c, c);
}
);
return bmp;
}
// Applies sepia toning to the provided image.
Bitmap* Sepiatone(Bitmap* bmp)
{
ProcessImage(bmp,
[](DWORD& color) {
BYTE r0, g0, b0;
GetRGB(color, r0, g0, b0);
WORD r1 = static_cast<WORD>((r0 * .393) + (g0 *.769) + (b0 * .189));
WORD g1 = static_cast<WORD>((r0 * .349) + (g0 *.686) + (b0 * .168));
WORD b1 = static_cast<WORD>((r0 * .272) + (g0 *.534) + (b0 * .131));
color = MakeColor(min(0xff, r1), min(0xff, g1), min(0xff, b1));
}
);
return bmp;
}
// Applies the given color mask to each pixel in the provided image.
Bitmap* ColorMask(Bitmap* bmp, DWORD mask)
{
ProcessImage(bmp,
[mask](DWORD& color) {
color = color & mask;
}
);
return bmp;
}
// Darkens the provided image by the given amount.
Bitmap* Darken(Bitmap* bmp, unsigned int percent)
{
if (percent > 100)
throw invalid_argument("Darken: percent must less than 100.");
double factor = percent / 100.0;
ProcessImage(bmp,
[factor](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
r = static_cast<BYTE>(factor*r);
g = static_cast<BYTE>(factor*g);
b = static_cast<BYTE>(factor*b);
color = MakeColor(r, g, b);
}
);
return bmp;
}
// Determines which color component (red, green, or blue) is most dominant
// in the given image and returns a corresponding color mask.
DWORD GetColorDominance(Bitmap* bmp)
{
// The ProcessImage function processes the image in parallel.
// The following combinable objects enable the callback function
// to increment the color counts without using a lock.
combinable<unsigned int> reds;
combinable<unsigned int> greens;
combinable<unsigned int> blues;
ProcessImage(bmp,
[&](DWORD& color) {
BYTE r, g, b;
GetRGB(color, r, g, b);
if (r >= g && r >= b)
reds.local()++;
else if (g >= r && g >= b)
greens.local()++;
else
blues.local()++;
}
);
// Determine which color is dominant and return the corresponding
// color mask.
unsigned int r = reds.combine(plus<unsigned int>());
unsigned int g = greens.combine(plus<unsigned int>());
unsigned int b = blues.combine(plus<unsigned int>());
if (r + r >= g + b)
return 0x00ff0000;
else if (g + g >= r + b)
return 0x0000ff00;
else
return 0x000000ff;
}
// Retrieves the class identifier for the given MIME type of an encoder.
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = nullptr;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == nullptr)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}
// 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&);
};
// Demonstrates how to set up a message network that performs a series of
// image processing operations on each JPEG image in the given directory and
// saves each altered image as a Windows bitmap.
void ProcessImages(const wstring& directory)
{
// Holds the number of active image processing operations and
// signals to the main thread that processing is complete.
countdown_event active(0);
// Maps Bitmap objects to their original file names.
map<Bitmap*, wstring> bitmap_file_names;
//
// 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();
});
//
// 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);
// 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);
// Wait for all operations to finish.
active.wait();
}
int wmain()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// Initialize GDI+.
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
// Perform image processing.
// TODO: Change this path if necessary.
ProcessImages(L"C:\\Users\\Public\\Pictures\\Sample Pictures");
// Shutdown GDI+.
GdiplusShutdown(gdiplusToken);
}
Örnek Çıktı aşağıda gösterilmiştir. Her kaynak görüntüye, ilgili değiştirilen görüntüdür.
Lighthouse Tom Alphin tarafından yazılmış ve bu nedenle gri tonlamaya dönüştürülür. Chrysanthemum, Çöl, Koala, ve Tulips baskın renk olarak kırmızı varsa ve bu nedenle mavi ve yeşil renk bileşenlerini kaldırmış olması ve koyu. Hydrangeas, Jellyfish, ve Penguins varsayılan ölçütlere uyan ve bu nedenle toned sepia.
Top
Kod Derleniyor
Örnek kodu kopyalayın ve Visual Studio Project'te yapıştırın veya adlı bir dosyaya yapıştırın görüntü işleme network.cpp ve Visual Studio komut istemi penceresinde aşağıdaki komutu çalıştırın.
cl.exe /DUNICODE /EHsc image-processing-network.cpp /link gdiplus.lib