Skip to content

Commit ef2193d

Browse files
committed
added new datatype yarp::sig::LayeredImage with test
modified yarpopencvdisplay to support `yarp::sig::LayeredImage` added yarp::sig::utils::sum() to transform a`yarp::sig::LayeredImage` to `yarp::sig::Image`
1 parent ba79e30 commit ef2193d

File tree

7 files changed

+605
-29
lines changed

7 files changed

+605
-29
lines changed

src/libYARP_sig/src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ set(YARP_sig_HDRS
1616
yarp/sig/ImageNetworkHeader.h
1717
yarp/sig/ImageUtils.h
1818
yarp/sig/IntrinsicParams.h
19+
yarp/sig/LayeredImage.h
1920
yarp/sig/LaserMeasurementData.h
2021
yarp/sig/Matrix.h
2122
yarp/sig/PointCloud.h
@@ -40,6 +41,7 @@ set(YARP_sig_SRCS
4041
yarp/sig/ImageUtils.cpp
4142
yarp/sig/IntrinsicParams.cpp
4243
yarp/sig/LaserMeasurementData.cpp
44+
yarp/sig/LayeredImage.cpp
4345
yarp/sig/Matrix.cpp
4446
yarp/sig/PointCloudBase.cpp
4547
yarp/sig/PointCloudUtils.cpp

src/libYARP_sig/src/yarp/sig/ImageUtils.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <yarp/sig/ImageUtils.h>
77
#include <cstring>
88
#include <algorithm> // std::math
9+
#include <yarp/os/Log.h>
10+
#include <yarp/os/LogStream.h>
911

1012
using namespace yarp::sig;
1113

@@ -141,3 +143,68 @@ bool utils::cropRect(const yarp::sig::Image& inImg,
141143

142144
return true;
143145
}
146+
147+
bool utils::sum(Image& OutImg, const Image& InImg, bool enable_colorkey, int colorkey, bool enable_alpha, float alpha, size_t offset_x, size_t offset_y)
148+
{
149+
if (OutImg.getPixelCode() != InImg.getPixelCode())
150+
{
151+
yError() << "utils::sum() Input and Output images must have the same pixelcode";
152+
return false;
153+
}
154+
155+
if (InImg.getPixelCode() != VOCAB_PIXEL_RGB)
156+
{
157+
yError() << "utils::sum() Unimplemented pixelcode";
158+
return false;
159+
}
160+
161+
yarp::sig::PixelRgb ColorkeyRGB;
162+
ColorkeyRGB.r = colorkey;
163+
ColorkeyRGB.g = colorkey;
164+
ColorkeyRGB.b = colorkey;
165+
166+
size_t yis = InImg.height();
167+
size_t xis = InImg.width();
168+
size_t yos = OutImg.height();
169+
size_t xos = OutImg.width();
170+
171+
for (size_t y = 0; y < yis; ++y)
172+
{
173+
for (size_t x = 0; x < xis; ++x)
174+
{
175+
size_t xo = x + offset_x;
176+
size_t yo = y + offset_y;
177+
if (xo > xos) {
178+
xo = xos;
179+
}
180+
if (yo > yos) {
181+
yo = yos;
182+
}
183+
184+
unsigned char* layer_pointer = InImg.getPixelAddress(x, y);
185+
unsigned char* outimg_pointer = OutImg.getPixelAddress(xo, yo);
186+
187+
yarp::sig::PixelRgb* layer_pointer_rgb = reinterpret_cast<yarp::sig::PixelRgb*>(layer_pointer);
188+
yarp::sig::PixelRgb* outimg_pointer_rgb = reinterpret_cast<yarp::sig::PixelRgb*>(outimg_pointer);
189+
190+
if (enable_colorkey && layer_pointer_rgb->r == ColorkeyRGB.r && layer_pointer_rgb->g == ColorkeyRGB.g && layer_pointer_rgb->b == ColorkeyRGB.b)
191+
{
192+
continue;
193+
}
194+
else if (enable_alpha)
195+
{
196+
outimg_pointer_rgb->r = layer_pointer_rgb->r * alpha + outimg_pointer_rgb->r * (1 - alpha);
197+
outimg_pointer_rgb->g = layer_pointer_rgb->g * alpha + outimg_pointer_rgb->g * (1 - alpha);
198+
outimg_pointer_rgb->b = layer_pointer_rgb->b * alpha + outimg_pointer_rgb->b * (1 - alpha);
199+
}
200+
else
201+
{
202+
outimg_pointer_rgb->r = layer_pointer_rgb->r;
203+
outimg_pointer_rgb->g = layer_pointer_rgb->g;
204+
outimg_pointer_rgb->b = layer_pointer_rgb->b;
205+
}
206+
}
207+
}
208+
209+
return true;
210+
}

src/libYARP_sig/src/yarp/sig/ImageUtils.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,28 @@ bool YARP_sig_API cropRect(const yarp::sig::Image& inImg,
6767
const std::pair<unsigned int, unsigned int>& vertex1,
6868
const std::pair<unsigned int, unsigned int>& vertex2,
6969
yarp::sig::Image& outImg);
70+
71+
/**
72+
* @brief applies an image on the top over another image.
73+
* @param[in/out] OutImg the output image. It must be a valid image on the top of which data will be summed. It may contain a backgroud or it can be zero.
74+
* @param[in] InImg the layer to be applied
75+
* @param[in] colorkey colorkey for the InImg image. If a pixel is == colorkey, then it will be made transparent and the backgroud will be visible.
76+
* @param[in] alpha to be applied to InImg.
77+
* @param[in] off_x horizontal offset applied to InImg. Excess will be cropped.
78+
* @param[in] off_y vertical offset applied to InImg. Excess will be cropped.
79+
* @note The two images must have the same pixelCode.
80+
* @return true on success, false if image cannot be summed because of incompatible format.
81+
*/
82+
bool YARP_sig_API sum(yarp::sig::Image& OutImg,
83+
const yarp::sig::Image& InImg,
84+
bool colorkey_enable,
85+
int colorkey,
86+
bool alpha_enable,
87+
float alpha,
88+
size_t off_x,
89+
size_t off_y);
90+
7091
} // namespace yarp::sig::utils
7192

93+
7294
#endif // YARP_SIG_IMAGEUTILS_H
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024-2024 Istituto Italiano di Tecnologia (IIT)
3+
* SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
6+
#include <yarp/sig/Image.h>
7+
#include <yarp/sig/ImageNetworkHeader.h>
8+
9+
#include <yarp/os/Bottle.h>
10+
#include <yarp/os/ConnectionReader.h>
11+
#include <yarp/os/ConnectionWriter.h>
12+
#include <yarp/os/Log.h>
13+
#include <yarp/os/Time.h>
14+
#include <yarp/os/Vocab.h>
15+
#include <yarp/os/LogStream.h>
16+
17+
#include <yarp/sig/LayeredImage.h>
18+
#include <yarp/sig/ImageUtils.h>
19+
20+
#include <cstdio>
21+
#include <cstring>
22+
#include <string>
23+
#include <utility>
24+
25+
#include <opencv2/opencv.hpp>
26+
27+
using namespace yarp::sig;
28+
using namespace yarp::os;
29+
30+
inline void writeToConnection(const Image& img, ConnectionWriter& connection)
31+
{
32+
ImageNetworkHeader imghdr;
33+
34+
imghdr.setFromImage(img);
35+
size_t hdrsize = sizeof(imghdr);
36+
connection.appendInt32(BOTTLE_TAG_BLOB);
37+
connection.appendInt32(hdrsize);
38+
connection.appendBlock((char*)(&imghdr), hdrsize);
39+
40+
size_t imgsize = img.getRawImageSize();
41+
connection.appendInt32(BOTTLE_TAG_BLOB);
42+
connection.appendInt32(imgsize);
43+
connection.appendBlock((char*)(img.getRawImage()), imgsize);
44+
45+
return;
46+
}
47+
48+
inline bool readFromConnection(FlexImage& dest, ConnectionReader& connection)
49+
{
50+
bool ok = true;
51+
ImageNetworkHeader imghdr;
52+
53+
connection.expectInt32();
54+
size_t sizeData = connection.expectInt32();
55+
ok &= connection.expectBlock((char*)(&imghdr), sizeData);
56+
if (!ok) { return false; }
57+
imghdr.setToImage(dest);
58+
59+
connection.expectInt32();
60+
size_t sizeImg = connection.expectInt32();
61+
size_t psizeImg = dest.getRawImageSize();
62+
if (sizeImg != psizeImg)
63+
{
64+
return false;
65+
}
66+
unsigned char* pImg = dest.getRawImage();
67+
ok &= connection.expectBlock((char*)pImg, sizeImg);
68+
69+
return ok;
70+
}
71+
72+
LayeredImage::LayeredImage()
73+
{
74+
}
75+
76+
77+
LayeredImage::~LayeredImage()
78+
{
79+
}
80+
81+
82+
void LayeredImage::clear()
83+
{
84+
background.zero();
85+
layers.clear();
86+
}
87+
88+
bool LayeredImage::read(yarp::os::ConnectionReader& connection)
89+
{
90+
bool ok = true;
91+
92+
connection.convertTextMode();
93+
94+
// LIST OF ELEMENTS
95+
connection.expectInt32();
96+
size_t elems = connection.expectInt32();
97+
98+
//ELEMENT 1
99+
connection.expectInt32();
100+
size_t layersNum = connection.expectInt32();
101+
if (elems != 1 + (1 * 2) + (layersNum*10))
102+
{
103+
return false;
104+
}
105+
106+
// ELEMENT 2-3
107+
ok &= readFromConnection(background, connection);
108+
109+
// ELEMENT 4-...
110+
// each layer contains 8+2 elems
111+
layers.clear();
112+
for (size_t i = 0; i < layersNum; i++)
113+
{
114+
yarp::sig::ImageLayer::colorkey_s colorkey = yarp::sig::ImageLayer::colorkey_s {};
115+
yarp::sig::ImageLayer::alpha_s alpha = yarp::sig::ImageLayer::alpha_s {};
116+
117+
connection.expectInt32();
118+
int32_t enable_val = connection.expectInt8(); //1
119+
connection.expectInt32();
120+
colorkey.enable = connection.expectInt8(); //2
121+
connection.expectInt32();
122+
colorkey.value = connection.expectInt32(); //3
123+
connection.expectInt32();
124+
alpha.enable = connection.expectInt8(); //4
125+
connection.expectInt32();
126+
alpha.value = connection.expectFloat32(); // 5
127+
connection.expectInt32();
128+
bool can_be_compressed = connection.expectInt8(); //6
129+
connection.expectInt32();
130+
int32_t offset_x = connection.expectInt32(); //7
131+
connection.expectInt32();
132+
int32_t offset_y = connection.expectInt32(); //8
133+
134+
FlexImage fleximg;
135+
ok &= readFromConnection(fleximg, connection); //9-10
136+
yarp::sig::ImageLayer oneLayer(fleximg, enable_val, colorkey, alpha, can_be_compressed, offset_x, offset_y);
137+
layers.emplace_back(oneLayer);
138+
}
139+
140+
return true;
141+
}
142+
143+
144+
bool LayeredImage::write(yarp::os::ConnectionWriter& connection) const
145+
{
146+
bool ok = true;
147+
size_t layers_num = layers.size();
148+
149+
//LIST OF ELEMENTS
150+
connection.appendInt32(BOTTLE_TAG_LIST);
151+
connection.appendInt32(1+(1*2)+(layers_num*10));
152+
153+
//ELEMENT 1
154+
connection.appendInt32(BOTTLE_TAG_INT32);
155+
connection.appendInt32(layers_num);
156+
157+
// ELEMENT 2-3
158+
writeToConnection(background, connection);
159+
160+
// ELEMENT 4-...
161+
// each layer contains 8+2 elems
162+
for (size_t i = 0; i < layers_num; i++)
163+
{
164+
connection.appendInt32(BOTTLE_TAG_INT8); //1
165+
connection.appendInt8 (layers[i].enable);
166+
connection.appendInt32(BOTTLE_TAG_INT8); //2
167+
connection.appendInt8(layers[i].colorkey.enable);
168+
connection.appendInt32(BOTTLE_TAG_INT32); //3
169+
connection.appendInt32(layers[i].colorkey.value);
170+
connection.appendInt32(BOTTLE_TAG_INT8); //4
171+
connection.appendInt8(layers[i].alpha.enable);
172+
connection.appendInt32(BOTTLE_TAG_FLOAT32); //5
173+
connection.appendFloat32(layers[i].alpha.value);
174+
connection.appendInt32(BOTTLE_TAG_INT8); //6
175+
connection.appendInt8(layers[i].can_be_compressed);
176+
connection.appendInt32(BOTTLE_TAG_INT32); //7
177+
connection.appendInt32(layers[i].offset_x);
178+
connection.appendInt32(BOTTLE_TAG_INT32); //8
179+
connection.appendInt32(layers[i].offset_y);
180+
writeToConnection(layers[i].layer, connection); // 9-10
181+
}
182+
183+
connection.convertTextMode();
184+
return !connection.isError();
185+
}
186+
187+
188+
LayeredImage::LayeredImage(const LayeredImage& alt) :
189+
Portable()
190+
{
191+
background = alt.background;
192+
this->layers = alt.layers;
193+
}
194+
195+
LayeredImage::LayeredImage(LayeredImage&& other) noexcept
196+
{
197+
}
198+
199+
LayeredImage& LayeredImage::operator=(const LayeredImage& alt)
200+
{
201+
background = alt.background;
202+
this->layers = alt.layers;
203+
return *this;
204+
}
205+
206+
bool LayeredImage::operator==(const LayeredImage& alt) const
207+
{
208+
size_t l1 = this->layers.size();
209+
size_t l2 = alt.layers.size();
210+
211+
if (l1 != l2)
212+
{
213+
return false;
214+
}
215+
216+
if (background != alt.background)
217+
{
218+
return false;
219+
}
220+
221+
for (size_t i = 0; i < l1; i++)
222+
{
223+
if ((this->layers[i].enable != alt.layers[i].enable) ||
224+
(this->layers[i].colorkey.enable != alt.layers[i].colorkey.enable) ||
225+
(this->layers[i].colorkey.value != alt.layers[i].colorkey.value) ||
226+
(this->layers[i].alpha.enable != alt.layers[i].alpha.enable) ||
227+
(fabs(this->layers[i].alpha.value - alt.layers[i].alpha.value) > 0.001) ||
228+
(this->layers[i].layer != alt.layers[i].layer) ||
229+
(this->layers[i].can_be_compressed != alt.layers[i].can_be_compressed) ||
230+
(this->layers[i].offset_x != alt.layers[i].offset_x) ||
231+
(this->layers[i].offset_y != alt.layers[i].offset_y))
232+
{
233+
return false;
234+
}
235+
}
236+
237+
return true;
238+
}
239+
240+
yarp::sig::FlexImage LayeredImage::convert_to_flexImage()
241+
{
242+
yarp::sig::FlexImage outimg = background;
243+
244+
bool ret = true;
245+
for (size_t i = 0; i < this->layers.size(); i++)
246+
{
247+
if (layers[i].enable == false)
248+
{
249+
continue;
250+
}
251+
252+
ret &= yarp::sig::utils::sum(outimg, layers[i].layer, layers[i].colorkey.enable, layers[i].colorkey.value, layers[i].alpha.enable, layers[i].alpha.value, layers[i].offset_x, layers[i].offset_y);
253+
}
254+
255+
return outimg;
256+
}
257+
258+
LayeredImage::operator yarp::sig::FlexImage()
259+
{
260+
return convert_to_flexImage();
261+
}

0 commit comments

Comments
 (0)