Skip to content

Commit

Permalink
Merge pull request #1474 from Ashheer/image-edgedetect
Browse files Browse the repository at this point in the history
Image edgedetect
  • Loading branch information
zhouhang95 authored Oct 17, 2023
2 parents 9b8aece + bc21a5f commit cb11e10
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 160 deletions.
59 changes: 30 additions & 29 deletions projects/ImgCV/ImageComposite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,22 +573,22 @@ ZENDEFNODE(Composite, {


template <class T>
static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, const T& rgb2, const vec3f opacity, std::string compmode)
static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, const T& rgb2, const T& background, const vec3f opacity, std::string compmode)
{
if(compmode == std::string("Copy")) {//copy and over is different!
T value = rgb1 * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Over")) {
T value = (rgb1 + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (rgb1 + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Under")) {
T value = (rgb2 + rgb1 * (1 - alpha2)) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (background + rgb1 * (1 - alpha2)) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Atop")) {
T value = (rgb1 * alpha2 + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (rgb1 * alpha2 + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("In")) {
Expand All @@ -600,53 +600,53 @@ static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, cons
return value;
}
else if(compmode == std::string("Xor")) {
T value = (rgb1 * (1 - alpha2) + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (rgb1 * (1 - alpha2) + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Add")) {
T value = (rgb1 + rgb2) * opacity[0] + rgb2 * (1 - opacity[0]);//clamp?
T value = (rgb1 + background) * opacity[0] + rgb2 * (1 - opacity[0]);//clamp?
return value;
}
else if(compmode == std::string("Subtract")) {
T value = (rgb2 - rgb1) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (background - rgb1) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Multiply")) {
T value = rgb1 * rgb2 * opacity[0] + rgb2 * (1 - opacity[0]);
T value = rgb1 * background * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Max(Lighten)")) {
T value = zeno::max(rgb1, rgb2) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = zeno::max(rgb1, background) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Min(Darken)")) {
T value = zeno::min(rgb1, rgb2) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = zeno::min(rgb1, background) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Screen")) {//A+B-AB if A and B between 0-1, else A if A>B else B
T value = (1 - (1 - rgb2) * (1 - rgb1)) * opacity[0] + rgb2 * (1 - opacity[0]);//only care 0-1!
T value = (1 - (1 - background) * (1 - rgb1)) * opacity[0] + rgb2 * (1 - opacity[0]);//only care 0-1!
return value;
}
else if(compmode == std::string("Difference")) {
T value = zeno::abs(rgb1 - rgb2) * opacity[0] + rgb2 * (1 - opacity[0]);
T value = zeno::abs(rgb1 - background) * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
else if(compmode == std::string("Average")) {
T value = (rgb1 + rgb2) / 2 * opacity[0] + rgb2 * (1 - opacity[0]);
T value = (rgb1 + background) / 2 * opacity[0] + rgb2 * (1 - opacity[0]);
return value;
}
return T(0);
}

static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const vec3f& rgb1, const vec3f& rgb2, const vec3f opacity, std::string compmode)
static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const vec3f& rgb1, const vec3f& rgb2, const vec3f& background, const vec3f opacity, std::string compmode)
{
if(compmode == std::string("Overlay")) {
vec3f value;
for (int k = 0; k < 3; k++) {
if (rgb2[k] < 0.5) {
value[k] = 2 * rgb1[k] * rgb2[k];
value[k] = 2 * rgb1[k] * background[k];
} else {
value[k] = 1 - 2 * (1 - rgb1[k]) * (1 - rgb2[k]);//screen
value[k] = 1 - 2 * (1 - rgb1[k]) * (1 - background[k]);//screen
}
}
value = value * opacity[0] + rgb2 * (1 - opacity[0]);
Expand All @@ -656,9 +656,9 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve
vec3f value;
for (int k = 0; k < 3; k++) {
if (rgb1[k] < 0.5) {
value[k] = 2 * rgb1[k] * rgb2[k] + rgb2[k] * rgb2[k] * (1 - 2 * rgb1[k]);
value[k] = 2 * rgb1[k] * background[k] + background[k] * background[k] * (1 - 2 * rgb1[k]);
} else {
value[k] = 2 * rgb2[k] * (1 - rgb1[k]) + sqrt(rgb2[k]) * (2 * rgb1[k] - 1);
value[k] = 2 * background[k] * (1 - rgb1[k]) + sqrt(background[k]) * (2 * rgb1[k] - 1);
}
}
/*for (int k = 0; k < 3; k++) { Nuke method
Expand All @@ -677,7 +677,7 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve
if (rgb1[k] == 0) {
value[k] = 1;
} else {
value[k] = rgb2[k] / rgb1[k];
value[k] = background[k] / rgb1[k];
}
}
value = value * opacity[0] + rgb2 * (1 - opacity[0]);
Expand All @@ -686,7 +686,7 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve
return zeno::vec3f(0);
}

struct Blend: INode {
struct Blend: INode {//optimize
virtual void apply() override {//todo:: add blend scope RGBA and Premultiplied / Alpha Blending(https://github.com/jamieowen/glsl-blend/issues/6)
auto blend = get_input<PrimitiveObject>("Foreground");
auto base = get_input<PrimitiveObject>("Background");
Expand Down Expand Up @@ -726,20 +726,20 @@ struct Blend: INode {
auto &blendalpha = blend->has_attr("alpha")?blend->attr<float>("alpha"):std::vector<float>(imagesize, 1.0f);
auto &basealpha = base->has_attr("alpha")?base->attr<float>("alpha"):std::vector<float>(imagesize, 1.0f);

//todo: rgb1和rgb2大小不同的情况
#pragma omp parallel for
for (int i = 0; i < imagesize; i++) {
vec3f rgb1 = blend->verts[i] * opacity1;
vec3f rgb2 = base->verts[i] * opacity2;
vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity;
float alpha1 = zeno::clamp(blendalpha[i], 0, 1);
float alpha2 = zeno::clamp(basealpha[i], 0, 1);
vec3f rgb2 = base->verts[i];
vec3f background = rgb2 * opacity2;
vec3f opacity = zeno::clamp(mask->verts[i] * maskopacity, 0, 1);
float alpha1 = zeno::clamp(blendalpha[i] * opacity1, 0, 1);
float alpha2 = zeno::clamp(basealpha[i] * opacity2, 0, 1);
if(compmode == "Overlay" || compmode == "SoftLight" || compmode == "Divide"){
vec3f c = BlendModeV(alpha1, alpha2, rgb1, rgb2, opacity, compmode);
vec3f c = BlendModeV(alpha1, alpha2, rgb1, rgb2, background, opacity, compmode);
image2->verts[i] = c;
}
else{
vec3f c = BlendMode<zeno::vec3f>(alpha1, alpha2, rgb1, rgb2, opacity, compmode);
vec3f c = BlendMode<zeno::vec3f>(alpha1, alpha2, rgb1, rgb2, background, opacity, compmode);
image2->verts[i] = c;
}
}
Expand All @@ -749,8 +749,9 @@ struct Blend: INode {
//std::string alphablendmode = alphamode == "SameWithBlend" ? compmode : alphamode;
#pragma omp parallel for
for (int i = 0; i < imagesize; i++) {
vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity;
float alpha = BlendMode<float>(zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), opacity, alphamode);
vec3f opacity = zeno::clamp(mask->verts[i] * maskopacity, 0, 1);
float alpha = BlendMode<float>(zeno::clamp(blendalpha[i] * opacity1, 0, 1), zeno::clamp(basealpha[i], 0, 1),
zeno::clamp(blendalpha[i] * opacity1, 0, 1), zeno::clamp(basealpha[i], 0, 1), zeno::clamp(basealpha[i] * opacity2, 0, 1), opacity, alphamode);
image2alpha[i] = alpha;
}
}
Expand Down
146 changes: 15 additions & 131 deletions projects/ImgCV/ObjectRecog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ struct ImageEdgeDetect : INode {
int threshold = get_input2<int>("threshold");
int maxThreshold = get_input2<int>("maxThreshold");
float kernelSize = get_input2<float>("kernelSize");
//float scale = get_input2<float>("scale");
//float delta = get_input2<float>("delta");
//int borderType = get_input2<int>("borderType");
auto &ud = image->userData();
int w = ud.get2<int>("w");
int h = ud.get2<int>("h");
Expand Down Expand Up @@ -130,61 +133,26 @@ struct ImageEdgeDetect : INode {
}
set_output("image", image);
}
if (mode == "sobel_gray") {
if (mode == "sobel") {//todo::
cv::Mat imagecvin(h, w, CV_32F);
cv::Mat imagecvout(h, w, CV_32F);
int var = 1;
float grayvalue = 1;
#pragma omp parallel for
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
vec3f rgb = image->verts[i * w + j];
var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114) ;//average convert to gray
imagecvin.at<float>(i, j) = var;
grayvalue = rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114;//todo detect rgb three channel?
imagecvin.at<float>(i, j) = grayvalue;
}
}

cv::Mat gradX, gradY;
//cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize,scale,delta,borderType);
cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize);
cv::Sobel(imagecvin, gradY, CV_32F, 0, 1, kernelSize);
cv::convertScaleAbs(gradX, gradX);
cv::convertScaleAbs(gradY, gradY);

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float xg = gradX.at<uchar>(i, j);
float yg = gradY.at<uchar>(i, j);
float xy = xg + yg;
xy = xy / 255.f;
image->verts[i * w + j] = {xy, xy, xy};
}
}
set_output("image", image);
}

if (mode == "sobel_threshold") {
cv::Mat imagecvin(h, w, CV_32F);
cv::Mat imagecvout(h, w, CV_32F);
int var = 1;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
vec3f rgb = image->verts[i * w + j];
var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114);
imagecvin.at<float>(i, j) = var;
}
}

cv::Mat gradX, gradY;
cv::Sobel(imagecvin, gradX, CV_32F, 1, 0);
cv::Sobel(imagecvin, gradY, CV_32F, 0, 1);

cv::Mat gradientMagnitude, gradientDirection;
cv::cartToPolar(gradX, gradY, gradientMagnitude, gradientDirection, true);

cv::threshold(gradientMagnitude, imagecvout, threshold, maxThreshold, cv::THRESH_BINARY);
#pragma omp parallel for
for (int i = 0; i < h; i++) {

for (int j = 0; j < w; j++) {
float r = float(imagecvout.at<float>(i, j)) / 255.f;
image->verts[i * w + j] = {r, r, r};
float magnitude = abs(gradX.at<float>(i, j)) + abs(gradY.at<float>(i, j));//manhattan distance? not euclidean distance
image->verts[i * w + j] = {magnitude, magnitude, magnitude};
}
}
set_output("image", image);
Expand Down Expand Up @@ -359,7 +327,7 @@ struct ImageEdgeDetect : INode {
ZENDEFNODE(ImageEdgeDetect, {
{
{ "image" },
{ "enum zeno_gray zeno_threshold sobel_gray sobel_threshold roberts_gray roberts_threshold prewitt_gray prewitt_threshold canny_gray canny_threshold", "mode", "sobel_gray" },
{ "enum zeno_gray zeno_threshold sobel roberts_gray roberts_threshold prewitt_gray prewitt_threshold canny_gray canny_threshold", "mode", "sobel" },
{ "float", "threshold", "50" },
{ "float", "maxThreshold", "9999" },
{ "float", "kernelSize", "3"}
Expand Down Expand Up @@ -472,91 +440,7 @@ ZENDEFNODE(ImageEdgeDetectDIY, {
{ "deprecated" },
});

struct ImageEdgeDetectSobel : INode {
void apply() override {
std::shared_ptr<PrimitiveObject> image = get_input2<PrimitiveObject>("image");
auto mode = get_input2<std::string>("mode");
int threshold = get_input2<int>("threshold");
int maxThreshold = get_input2<int>("maxThreshold");
float kernelSize = get_input2<float>("kernelSize");
auto &ud = image->userData();
int w = ud.get2<int>("w");
int h = ud.get2<int>("h");

if (mode == "sobel_gray") {
cv::Mat imagecvin(h, w, CV_32F);
cv::Mat imagecvout(h, w, CV_32F);
int var = 1;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
vec3f rgb = image->verts[i * w + j];
var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114) ;//average convert to gray
imagecvin.at<float>(i, j) = var;
}
}

cv::Mat gradX, gradY;
cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize);
cv::Sobel(imagecvin, gradY, CV_32F, 0, 1, kernelSize);
cv::convertScaleAbs(gradX, gradX);
cv::convertScaleAbs(gradY, gradY);

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float xg = gradX.at<uchar>(i, j);
float yg = gradY.at<uchar>(i, j);
float xy = xg + yg;
xy = xy / 255.f;
image->verts[i * w + j] = {xy, xy, xy};
}
}
set_output("image", image);
}

if (mode == "sobel_threshold") {
cv::Mat imagecvin(h, w, CV_32F);
cv::Mat imagecvout(h, w, CV_32F);
int var = 1;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
vec3f rgb = image->verts[i * w + j];
var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114);
imagecvin.at<float>(i, j) = var;
}
}
cv::Mat gradX, gradY;
cv::Sobel(imagecvin, gradX, CV_32F, 1, 0);
cv::Sobel(imagecvin, gradY, CV_32F, 0, 1);
cv::Mat gradientMagnitude, gradientDirection;
cv::cartToPolar(gradX, gradY, gradientMagnitude, gradientDirection, true);
cv::threshold(gradientMagnitude, imagecvout, threshold, maxThreshold, cv::THRESH_BINARY);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float r = float(imagecvout.at<float>(i, j)) / 255.f;
image->verts[i * w + j] = {r, r, r};
}
}
set_output("image", image);
}
}
};

ZENDEFNODE(ImageEdgeDetectSobel, {
{
{ "image" },
{ "enum sobel_gray sobel_threshold", "mode", "sobel_gray" },
{ "float", "threshold", "50" },
{ "float", "maxThreshold", "9999" },
{ "float", "kernelSize", "3"},
},
{
{ "image" }
},
{},
{ "image" },
});

struct ImageEdgeDetectMarr : INode {
struct ImageEdgeDetectMarr : INode { //need to gray?
void apply() override {
std::shared_ptr<PrimitiveObject> image = get_input2<PrimitiveObject>("image");
auto kerneldiameter = get_input2<int>("kernelDiameter");
Expand Down Expand Up @@ -589,7 +473,7 @@ struct ImageEdgeDetectMarr : INode {

if (kernelX >= 0 && kernelX < w && kernelY >= 0 && kernelY < h) {

sum += (image->verts[kernelY * w + kernelX][0]) * 255 * kernel[i][j];
sum += (image->verts[kernelY * w + kernelX][0]) * 255.99 * kernel[i][j];//maybe this cause problem
}
}
}
Expand Down

0 comments on commit cb11e10

Please sign in to comment.