Skip to content

Commit

Permalink
Merge pull request #2559 from PeterBowman/add_cropRect
Browse files Browse the repository at this point in the history
Add `yarp::sig::utils::cropRect()`, adopt in grabberDual
  • Loading branch information
drdanz authored Apr 28, 2021
2 parents dca3a0c + 9b74d02 commit 493d7a3
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 30 deletions.
11 changes: 11 additions & 0 deletions doc/release/master/add_cropRect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_cropRect {#master}
-----------

### Libraries

#### `sig`

##### `utils`

* Added `cropRect()` helper function for cropping a rectangle area out of an
image given two opposite vertices.
24 changes: 10 additions & 14 deletions src/devices/ServerFrameGrabberDual/ServerFrameGrabberDual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <yarp/dev/GenericVocabs.h>

#include <cstring>
#include <algorithm> // std::for_each

using namespace yarp::os;
using namespace yarp::dev;
Expand Down Expand Up @@ -525,13 +526,14 @@ bool ServerGrabber::respond(const yarp::os::Bottle& cmd,

// Default values here are valid for cases 1a and `left` side of 2a
IFrameGrabberImage *imageInterface = fgImage;
int u_offset = 0;

if(param.twoCameras == false) // a single HW source of images
{
imageInterface = fgImage;
if(left == false) // if left is false, implicitly split is true
u_offset = imageInterface->width()/2; // 1b
{
std::for_each(vertices.begin(), vertices.end(), [=](auto &pt) { pt.first += imageInterface->width() / 2; }); // 1b
}

}
else
Expand All @@ -541,21 +543,20 @@ bool ServerGrabber::respond(const yarp::os::Bottle& cmd,
if(left == false)
{
imageInterface = fgImage2;
u_offset = 0;
// no offset
}
}
else
{
if(vertices[0].first >= fgImage->width()) // 2b, right image
{
imageInterface = fgImage2;
u_offset = -fgImage->width();
std::for_each(vertices.begin(), vertices.end(), [=](auto &pt) { pt.first -= fgImage->width(); });
}
}

}


if(imageInterface != nullptr)
{
if(imageInterface->getImageCrop((cropType_id_t) cmd.get(3).asVocab(), vertices, cropped) )
Expand All @@ -576,16 +577,11 @@ bool ServerGrabber::respond(const yarp::os::Bottle& cmd,
ImageOf< PixelRgb > full;
imageInterface->getImage(full);

cropped.resize(vertices[1].first - vertices[0].first +1, vertices[1].second - vertices[0].second +1); // +1 to be inclusive
cropped.zero();
for(int u_in=vertices[0].first + u_offset, u_out=0; u_in<=vertices[1].first + u_offset; u_in++, u_out++)
if(!utils::cropRect(full, vertices[0], vertices[1], cropped))
{
for(int v_in=vertices[0].second, v_out=0; v_in <= vertices[1].second; v_in++, v_out++)
{
cropped.pixel(u_out, v_out).r = full.pixel(u_in, v_in).r;
cropped.pixel(u_out, v_out).g = full.pixel(u_in, v_in).g;
cropped.pixel(u_out, v_out).b = full.pixel(u_in, v_in).b;
}
response.addString("GetImageCrop failed: utils::cropRect error.");
yCError(SERVERGRABBER) << "GetImageCrop failed: utils::cropRect error";
return false;
}
}
else if(cmd.get(3).asVocab() == YARP_CROP_LIST)
Expand Down
33 changes: 33 additions & 0 deletions src/libYARP_sig/src/yarp/sig/ImageUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <yarp/sig/ImageUtils.h>
#include <cstring>
#include <algorithm> // std::math

using namespace yarp::sig;

Expand Down Expand Up @@ -111,3 +112,35 @@ bool utils::vertConcat(const Image& inImgUp, const Image& inImgDown, Image& outI
memcpy(outImg.getRawImage() + imgSize, inImgDown.getRawImage(), imgSize);
return true;
}

bool utils::cropRect(const yarp::sig::Image& inImg,
const std::pair<unsigned int, unsigned int>& vertex1,
const std::pair<unsigned int, unsigned int>& vertex2,
yarp::sig::Image& outImg)
{
if (inImg.getPixelCode() != outImg.getPixelCode()) {
return false;
}

// Normalize vertices: upper-left (tlx,tly) and bottom-right (brx,bry) corners
auto tlx = std::min(vertex1.first, vertex2.first);
auto tly = std::min(vertex1.second, vertex2.second);
auto brx = std::max(vertex1.first, vertex2.first);
auto bry = std::max(vertex1.second, vertex2.second);

if (!inImg.isPixel(brx, bry)) {
return false;
}

outImg.resize(brx - tlx + 1, bry - tly + 1); // width, height

auto * pixelOut = outImg.getRawImage();

for (unsigned int row = 0; row < outImg.height(); row++) {
const auto * pixelIn = inImg.getPixelAddress(tlx, tly + row);
memcpy(pixelOut, pixelIn, outImg.getRowSize());
pixelOut += outImg.getRowSize();
}

return true;
}
48 changes: 32 additions & 16 deletions src/libYARP_sig/src/yarp/sig/ImageUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef YARP_SIG_IMAGEUTILS_H
#define YARP_SIG_IMAGEUTILS_H

#include <utility> // std::pair
#include <yarp/sig/Image.h>

namespace yarp {
Expand All @@ -22,46 +23,61 @@ namespace utils
{

/**
* @brief vertSplit, split vertically an image in two images of the same size.
* @param inImg[in] image to be vertically split.
* @param outImgL[out] left half of inImg.
* @param outImgR[out] right half of inImg.
* @brief Split vertically an image in two images of the same size.
* @param[in] inImg image to be vertically split.
* @param[out] outImgL left half of inImg.
* @param[out] outImgR right half of inImg.
* @note The input image must have same height, double width of the output images and same pixel type.
* @return true on success, false otherwise.
*/
bool YARP_sig_API vertSplit(const yarp::sig::Image& inImg, yarp::sig::Image& outImgL, yarp::sig::Image& outImgR);

/**
* @brief horzSplit, split horizontally an image in two images of the same size.
* @param inImg[in] image to be horizontally split.
* @param outImgUp[out] top half of inImg.
* @param outImgDown[out] bottom half of inImg.
* @brief Split horizontally an image in two images of the same size.
* @param[in] inImg image to be horizontally split.
* @param[out] outImgUp top half of inImg.
* @param[out] outImgDown bottom half of inImg.
* @note The input image must have same height, double width of the output images and same pixel type.
* @return true on success, false otherwise.
*/
bool YARP_sig_API horzSplit(const yarp::sig::Image& inImg, yarp::sig::Image& outImgUp, yarp::sig::Image& outImgDown);

/**
* @brief horzConcat, concatenate horizontally two images of the same size in one with double width.
* @param inImgL[in] input left image.
* @param inImgR[in] input right image.
* @param outImg[out] result of the horizontal concatenation.
* @brief Concatenate horizontally two images of the same size in one with double width.
* @param[in] inImgL input left image.
* @param[in] inImgR input right image.
* @param[out] outImg result of the horizontal concatenation.
* @note The input images must have same dimensions and pixel type, and the output image must have same height and
* double width.
* @return true on success, false otherwise.
*/
bool YARP_sig_API horzConcat(const yarp::sig::Image& inImgL, const yarp::sig::Image& inImgR, yarp::sig::Image& outImg);

/**
* @brief vertConcat, concatenate vertically two images of the same size in one with double height.
* @param inImgUp[in] input top image.
* @param inImgDown[in] input bottom image.
* @param outImg[out] result of the horizontal concatenation.
* @brief Concatenate vertically two images of the same size in one with double height.
* @param[in] inImgUp input top image.
* @param[in] inImgDown input bottom image.
* @param[out] outImg result of the horizontal concatenation.
* @note The input images must have same dimensions and pixel type, and the output image must have same width and
* double height.
* @return true on success, false otherwise.
*/
bool YARP_sig_API vertConcat(const yarp::sig::Image& inImgUp, const yarp::sig::Image& inImgDown, yarp::sig::Image& outImg);

/**
* @brief Crop a rectangle area out of an image given two opposite vertices.
* @param[in] inImg input image.
* @param[in] vertex1 first vertex of the crop rectangle area.
* @param[in] vertex2 second vertex of the crop rectangle area.
* @param[out] outImg result of cropping the input image.
* @note Input and output images must have same pixel type and the crop area must lay within the input image. Vertices
* needn't be passed in the usual top-left, bottom-right order. The output image is resized to match the crop dimensions.
* @return true on success, false otherwise.
*/
bool YARP_sig_API cropRect(const yarp::sig::Image& inImg,
const std::pair<unsigned int, unsigned int>& vertex1,
const std::pair<unsigned int, unsigned int>& vertex2,
yarp::sig::Image& outImg);
} // namespace utils
} // namespace sig
} // namespace yarp
Expand Down
36 changes: 36 additions & 0 deletions tests/libYARP_sig/ImageTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,5 +743,41 @@ TEST_CASE("sig::ImageTest", "[yarp::sig]")
CHECK(ok); // Checking data consistency bottom split
}

SECTION("test image crop.")
{
ImageOf<PixelRgb> inImg, outImg;
inImg.resize(10, 10);

size_t tlx = 4;
size_t tly = 5;
size_t brx = 8;
size_t bry = 7;

PixelRgb pixelValue {255, 0, 0};

for (size_t u = tlx; u <= brx; u++) {
for (size_t v = tly; v <= bry; v++) {
inImg.pixel(u, v) = pixelValue;
}
}

CHECK(utils::cropRect(inImg, {tlx, tly}, {brx, bry}, outImg));

CHECK(outImg.width() == brx - tlx + 1);
CHECK(outImg.height() == bry - tly + 1);

bool ok = true;

for (size_t u = 0; u < outImg.width(); u++) {
for (size_t v = 0; v < outImg.height(); v++) {
ok &= outImg.pixel(u, v).r == pixelValue.r;
ok &= outImg.pixel(u, v).g == pixelValue.g;
ok &= outImg.pixel(u, v).b == pixelValue.b;
}
}

CHECK(ok);
}

NetworkBase::setLocalMode(false);
}

0 comments on commit 493d7a3

Please sign in to comment.