summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vispcb/class.c131
-rw-r--r--vispcb/class.h9
-rw-r--r--vispcb/gui.c18
3 files changed, 135 insertions, 23 deletions
diff --git a/vispcb/class.c b/vispcb/class.c
index dd62005..beea6f6 100644
--- a/vispcb/class.c
+++ b/vispcb/class.c
@@ -11,6 +11,7 @@
*/
+#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
@@ -20,32 +21,142 @@
#include "class.h"
-void classify(struct class *class, const struct ppm *ppm)
+struct class {
+ const char *name;
+
+ uint8_t r, g, b; /* RGB color */
+ uint8_t r0, r1; /* intensity */
+ uint8_t a; /* angle, in degrees */
+
+ float a_cos; /* cosine of angle */
+ uint16_t sr0, sr1; /* intensity, stretched */
+ float rad; /* radius */
+};
+
+
+#define N_CLASSES (sizeof(classes) / sizeof(classes[0]))
+
+
+static struct class classes[] = {
+ {
+ .name = "bg",
+ .r = 255,
+ .g = 255,
+ .b = 255,
+ .r0 = 200,
+ .r1 = 255,
+ .a = 20,
+ },
+ {
+ .name = "pcb",
+ .r = 0,
+ .g = 255,
+ .b = 200,
+ .a = 20,
+ .r0 = 80,
+ .r1 = 200,
+ },
+};
+
+
+static bool in_cone(const struct class *c, uint8_t r, uint8_t g, uint8_t b)
+{
+ unsigned scalar;
+ float rad;
+
+ if (!r && !g && !b)
+ return c->r0 == 0;
+ scalar = c->r * r + c->g * g + c->b * b;
+ rad = hypotf(hypotf(r, g), b);
+ if (scalar < c->a_cos * rad * c->rad)
+ return 0;
+ if (rad < c->sr0)
+ return 0;
+ if (rad > c->sr1)
+ return 0;
+ return 1;
+}
+
+
+void analyze(uint8_t r, uint8_t g, uint8_t b)
+{
+ float rad;
+ unsigned scalar;
+ const struct class *c;
+
+ fprintf(stderr, "RGB %u %u %u, ", r, g, b);
+ if (!r && !g && !b) {
+ fprintf(stderr, "r = 0\n");
+ return;
+ }
+ rad = hypotf(hypotf(r, g), b);
+ fprintf(stderr, "r = %g\n", rad);
+ for (c = classes; c != classes + N_CLASSES; c++) {
+ scalar = c->r * r + c->g * g + c->b * b;
+ fprintf(stderr, "\t%s:\t%f\n", c->name,
+ acos(scalar / rad / c->rad) / M_PI * 180);
+ }
+
+}
+
+
+static uint16_t stretch(uint8_t rad, uint8_t r, uint8_t g, uint8_t b)
+{
+ float f = 1, h;
+
+ if (r)
+ f /= cos(atan2(r, g));
+ h = hypotf(r, g);
+ if (h >= 1)
+ f /= cos(atan2(b, h));
+ return rad * f;
+}
+
+
+static void setup_class(struct class *c)
+{
+ c->a_cos = cos(c->a /180.0 * M_PI);
+ c->rad = hypotf(hypotf(c->r, c->g), c->b);
+ c->sr0 = stretch(c->r0, c->r, c->g, c->b);
+ c->sr1 = stretch(c->r1, c->r, c->g, c->b);
+
+ fprintf(stderr, "%s:\t%u %u %u, %u-%u, a %u\n",
+ c->name, c->r, c->g, c->b, c->r0, c->r1, c->a);
+ fprintf(stderr, "\tcos %g, r %g\n", c->a_cos, c->rad);
+ fprintf(stderr, "\tsr %u-%u\n", c->sr0, c->sr1);
+}
+
+
+void classify(struct classification *cls, const struct ppm *ppm)
{
uint8_t *c;
unsigned n_pix = ppm->x * ppm->y;
const uint8_t *p = ppm->data;
+ unsigned i;
uint8_t r, g, b;
- class->x = ppm->x;
- class->y = ppm->y;
- class->data = c = calloc(n_pix, 1);
+ cls->x = ppm->x;
+ cls->y = ppm->y;
+ cls->data = c = calloc(n_pix, 1);
if (!c) {
perror("malloc");
exit(1);
}
- while (c != class->data + n_pix) {
+ for (i = 0; i != N_CLASSES; i++)
+ setup_class(classes + i);
+
+ while (c != cls->data + n_pix) {
r = p[0];
g = p[1];
b = p[2];
p += 3;
- if (hypot(hypot(r, g), b) > 200)
- *c = class_bg;
- else if (g > 80)
- *c = class_pcb;
-
+ for (i = 0; i != N_CLASSES; i++)
+ if (in_cone(classes + i, r, g, b)) {
+ *c = i + 1;
+ break;
+ }
c++;
}
}
diff --git a/vispcb/class.h b/vispcb/class.h
index 19266db..6eb8d02 100644
--- a/vispcb/class.h
+++ b/vispcb/class.h
@@ -24,19 +24,20 @@ enum classes {
n_classes
};
-struct class {
+struct classification {
unsigned x, y;
uint8_t *data;
};
-static inline uint8_t class_get(const struct class *class,
+static inline uint8_t class_get(const struct classification *cls,
unsigned x, unsigned y)
{
- return class->data[y * class->x + x];
+ return cls->data[y * cls->x + x];
}
-void classify(struct class *class, const struct ppm *ppm);
+void analyze(uint8_t r, uint8_t g, uint8_t b);
+void classify(struct classification *cls, const struct ppm *ppm);
#endif /* !CLASS_H */
diff --git a/vispcb/gui.c b/vispcb/gui.c
index e97c942..f8dc2ec 100644
--- a/vispcb/gui.c
+++ b/vispcb/gui.c
@@ -43,7 +43,7 @@ static bool contrast = 0;
static void draw_image(SDL_Surface *s, const struct ppm *ppm,
- const struct class *class)
+ const struct classification *cls)
{
Sint16 xend, yend;
Sint16 x, y;
@@ -52,7 +52,7 @@ static void draw_image(SDL_Surface *s, const struct ppm *ppm,
yend = yorig + yres > ppm->y ? ppm->y - yorig : yres;
for (y = 0; y != yend; y++)
for (x = 0; x != xend; x++)
- if (!hide[class_get(class, xorig + x, yorig + y)])
+ if (!hide[class_get(cls, xorig + x, yorig + y)])
pixelColor(s, x, y,
contrast ? CONTRAST_RGBA :
ppm_rgb(ppm, xorig + x, yorig + y) << 8 |
@@ -71,10 +71,10 @@ static void draw_status(SDL_Surface *s)
static void draw(SDL_Surface *s, const struct ppm *ppm,
- const struct class *class)
+ const struct classification *cls)
{
SDL_FillRect(s, NULL, SDL_MapRGB(s->format, 0, 0, 0));
- draw_image(s, ppm, class);
+ draw_image(s, ppm, cls);
draw_status(s);
}
@@ -92,8 +92,8 @@ static void button_event(SDL_MouseButtonEvent *button, const struct ppm *ppm)
switch (button->button) {
case 1:
if (x < ppm->x && y < ppm->y)
- fprintf(stderr, "%u %u %u\n", ppm_r(ppm, x, y),
- ppm_g(ppm, x, y), ppm_b(ppm, x, y));
+ analyze(ppm_r(ppm, x, y), ppm_g(ppm, x, y),
+ ppm_b(ppm, x, y));
break;
case 2:
xorig = x - xh;
@@ -174,7 +174,7 @@ static bool event_loop(SDL_Surface **surf, const struct ppm *ppm)
void gui(const struct ppm *ppm)
{
SDL_Surface *surf;
- struct class class;
+ struct classification cls;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "SDL_init: %s\n", SDL_GetError());
@@ -191,11 +191,11 @@ void gui(const struct ppm *ppm)
xres = surf->w;
yres = surf->h;
- classify(&class, ppm);
+ classify(&cls, ppm);
while (1) {
SDL_LockSurface(surf);
- draw(surf, ppm, &class);
+ draw(surf, ppm, &cls);
SDL_UnlockSurface(surf);
SDL_UpdateRect(surf, 0, 0, 0, 0);
if (event_loop(&surf, ppm))