| 169 | } |
| 170 | |
| 171 | static void build_overlay(app_state& app) { |
| 172 | if (app.image.data.empty()) return; |
| 173 | int w = app.image.width; |
| 174 | int h = app.image.height; |
| 175 | |
| 176 | std::vector<uint8_t> overlay(w * h * 4); |
| 177 | for (int i = 0; i < w * h; ++i) { |
| 178 | overlay[4*i+0] = app.image.data[3*i+0]; |
| 179 | overlay[4*i+1] = app.image.data[3*i+1]; |
| 180 | overlay[4*i+2] = app.image.data[3*i+2]; |
| 181 | overlay[4*i+3] = 255; |
| 182 | } |
| 183 | |
| 184 | if (app.show_masks) { |
| 185 | for (size_t d = 0; d < app.result.detections.size(); ++d) { |
| 186 | const auto& det = app.result.detections[d]; |
| 187 | if (det.mask.data.empty()) continue; |
| 188 | const float* c = INSTANCE_COLORS[d % N_COLORS]; |
| 189 | float alpha = 0.4f; |
| 190 | |
| 191 | int mw = det.mask.width; |
| 192 | int mh = det.mask.height; |
| 193 | for (int y = 0; y < std::min(h, mh); ++y) { |
| 194 | for (int x = 0; x < std::min(w, mw); ++x) { |
| 195 | if (det.mask.data[y * mw + x] > 127) { |
| 196 | int idx = (y * w + x) * 4; |
| 197 | overlay[idx+0] = (uint8_t)(overlay[idx+0] * (1-alpha) + c[0]*255*alpha); |
| 198 | overlay[idx+1] = (uint8_t)(overlay[idx+1] * (1-alpha) + c[1]*255*alpha); |
| 199 | overlay[idx+2] = (uint8_t)(overlay[idx+2] * (1-alpha) + c[2]*255*alpha); |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | app.tex_overlay = upload_texture(overlay.data(), w, h, 4, app.tex_overlay); |
| 207 | } |
| 208 | |
| 209 | static void load_image(app_state& app, const char* path) { |
| 210 | snprintf(app.status, sizeof(app.status), "Loading image: %s", path); |
no test coverage detected