-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathGetBounds.cpp
More file actions
188 lines (143 loc) · 5.35 KB
/
GetBounds.cpp
File metadata and controls
188 lines (143 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// GetBounds - Michael Millspaugh
// www.tks-designs.com
#include "Bounds.h"
using namespace std;
static const char* const CLASS = "GetBounds"; // Name of the class (should be the same as the name of the final .dll file)
struct rowValues {
int first, last;
};
typedef struct rowValues Struct;
void GetBounds::_validate(bool for_real) {
copy_info(); // Output image will have the same properties as the input
info_.black_outside(_blackOutside);
Format format = input0().format();
Box inputbounds = Box(format.x(), format.y(), format.r(), format.t());
ImagePlane imagePlane = ImagePlane(inputbounds, true, channels);
RequestOutput reqData = RequestOutput();
getRequests(inputbounds, channels, 0, reqData);
input0().request(channels, 0);
Interest interest(input0(), inputbounds, imagePlane.channels(), true);
interest.unlock();
if (input0().real_valid() && !input0().inErrorState() && !input0().inInvalidState()) {
if (input0().tryValidate() && interest.valid()) {
//only do this if the input hash has changed
running(true);
getBounds(imagePlane, format, interest);
Box bounds(p[0], p[1], p[2], p[3]);
//dont do it if the box is zero or negative (not sure why thats happening)
if (bounds.area() >= 1) {
info_.set(bounds);
};
_lastHash = input0().hash();
running(false);
//Op::warning("Get Bounds set bounding box ");
}
}
//Op::warning("Get Bounds validated ");
}
void GetBounds::getRequests(const Box& box, const ChannelSet& channelsSet, int count, RequestOutput& reqData) {
return PlanarIop::getRequests(box, channelsSet, count, reqData);
}
void GetBounds::getBounds(ImagePlane& imagePlane, Format& format, Interest& interest) {
// these useful format variables are used later
const int fx = format.x();
const int fy = format.y();
const int fr = format.r();
const int ft = format.t();
const int height = ft - fy;
const int width = fr - fx;
bool yMinFound = false;
bool yMaxFound = false;
bool xFound = false;
bool xMaxFound = false;
//std::cerr << "operating on " + channels << std::endl;
//for each row
foreach(z, channels) {
static int chanNo = imagePlane.chanNo(z);
static string chanName = getName(z);
for (int y = imagePlane.bounds().y(); y != imagePlane.bounds().t(); y++) {
float maxValue = 0;
//std::cerr << " getBounds on " + chanName + ", row " + to_string(y) << std::endl;
//walk left to right
for (int x = imagePlane.bounds().x(); x != imagePlane.bounds().r(); x++) {
//bounds will never get smaller after a value is found, so we can break once we pass the found point
//if (xFound && x > p[0]) break;
float currentPixel = interest.at(x, y, z); //row[z][x];
//make zero if ignoring negatives
//if (_ignoreNegative && currentPixel < 0) { currentPixel = 0; }
try {
if (currentPixel > 0) {
if (currentPixel > maxValue) maxValue = currentPixel;
if (!xFound) {
//std::cerr << " found new max x " + to_string(currentPixel) + " at " + to_string(x) << std::endl;
p[0] = x - 1;
xFound = true;
}
else {
if (x < p[0]) { p[0] = x - _extra; }
}
break;
}
}
catch (...) {
//probably attempting to get image before image has actually loaded
Op::warning("Attempt to GetBounds before source is available");
abort();
};
};
//walk right to left
for (int x = imagePlane.bounds().r() + 1; x-- > 0; ) {
//bounds will never get smaller after a value is found, so we can break once we pass the found point
//if (xMaxFound && x < p[2]) break;
float currentPixel = interest.at(x, y, z);
//make zero if ignoring negatives
//if (_ignoreNegative && currentPixel < 0) { currentPixel = 0; }
if (currentPixel > 0) {
if (currentPixel > maxValue) maxValue = currentPixel;
if (!xMaxFound) {
p[2] = x;
xMaxFound = true;
}
else {
if (x > p[2]) { p[2] = x + _extra; }
}
break;
};
};
if (maxValue > 0) {
if (!yMinFound) {
p[1] = y - _extra;
yMinFound = true;
}
else {
p[3] = y + _extra;
}
};
if (maxValue == 0 && yMinFound && yMaxFound) {
p[3] = y + _extra;
yMaxFound = true;
}
//std::cerr << " current bbox : " + to_string(p[0]) + ", " + to_string(p[1]) + ", " + to_string(p[2]) + ", " + to_string(p[3]) << std::endl;
};
};
}
void GetBounds::renderStripe(ImagePlane& imagePlane)
{
input0().fetchPlane(imagePlane);
imagePlane.makeUnique();
//std::cerr << to_string(p[0]) + "," + to_string(p[1]) + "," + to_string(p[2]) + "," + to_string(p[3]) << std::endl;
}
void GetBounds::knobs(Knob_Callback f) {
ChannelSet_knob(f, &channels, "channels");SetFlags(f, Knob::EARLY_STORE);
Bool_knob(f, &_blackOutside, "black outside"); SetFlags(f, Knob::STARTLINE); SetFlags(f, Knob::ALWAYS_SAVE); SetFlags(f, Knob::EARLY_STORE);
Bool_knob(f, &_ignoreNegative, "ignore <0"); SetFlags(f, Knob::EARLY_STORE);
Int_knob(f, &_extra, "extra");
}
bool GetBounds::renderFullPlanes() {
//When renderFullPlanes() returns true, the plugin will never be given an image plane to fill that contains less than the full set of channels.
return true;
}
static Iop* build(Node* node) {
return new GetBounds(node);
}
const PlanarIop::Description GetBounds::dGet("GetBounds", "GetBounds", build); // Nuke reads this to get the name of your plugin in the UI. Make sure this is the same as the name of the class and the final .dll file!