Example #1
0
static void process_layer(state_t * state, vx_code_input_stream_t * cins)
{
    // update (or create) the layer_info_t

    int layer_id = cins->read_uint32(cins);
    int world_id = cins->read_uint32(cins);
    int draw_order = cins->read_uint32(cins);
    int bg_color = cins->read_uint32(cins);

    layer_info_t * linfo = NULL;
    zhash_get(state->layer_info_map, &layer_id, &linfo);


    if (linfo == NULL) {

        linfo = calloc(1,sizeof(layer_info_t));

        linfo->cam_mgr = default_cam_mgr_create();
        linfo->event_handler = default_event_handler_create(linfo->cam_mgr, UI_ANIMATE_MS);
        linfo->vp_mgr = vx_viewport_mgr_create();

        zhash_put(state->layer_info_map, &layer_id, &linfo, NULL, NULL);
    }

    linfo->layer_id = layer_id;
    linfo->draw_order = draw_order;

    bg_color+=world_id; // XXX unused variable
}
Example #2
0
vx_buffer_t * vx_world_get_buffer(vx_world_t * world, const char * name)
{
    vx_buffer_t * buffer = NULL;

    pthread_mutex_lock(&world->buffer_mutex);

    zhash_get(world->buffer_map, &name, &buffer);
    if (buffer == NULL) {
        buffer = calloc(1, sizeof(vx_buffer_t));

        buffer->name = strdup(name);
        buffer->world = world;
        buffer->draw_order = 0;

        buffer->back_objs = zarray_create(sizeof(vx_object_t*));
        buffer->pending_objs = zarray_create(sizeof(vx_object_t*));
        buffer->front_objs = zarray_create(sizeof(vx_object_t*));

        buffer->front_resc = zhash_create(sizeof(uint64_t), sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals);
        buffer->front_codes = vx_code_output_stream_create(128);

        pthread_mutex_init(&buffer->mutex, NULL);

        vx_buffer_t * oldBuffer= NULL;
        zhash_put(buffer->world->buffer_map, &buffer->name, &buffer, NULL, &oldBuffer);
        assert(oldBuffer == NULL);
    }

    pthread_mutex_unlock(&world->buffer_mutex);

    return buffer;
}
Example #3
0
void
eecs467_default_display_started (vx_application_t *app, vx_display_t *disp)
{
    eecs467_default_implementation_t *impl = app->impl;

    vx_layer_t *layer = vx_layer_create (impl->world);
    vx_layer_set_background_color (layer, vx_black);
    vx_layer_set_display (layer, disp);

    pthread_mutex_lock (&impl->mutex);
    // store a reference to the world and layer that we associate with each vx_display_t
    zhash_put (impl->layers, &disp, &layer, NULL, NULL);
    pthread_mutex_unlock (&impl->mutex);

    if (impl->vxeh != NULL)
        vx_layer_add_event_handler (layer, impl->vxeh);

    vx_layer_camera_op (layer, OP_PROJ_PERSPECTIVE);
    float eye[3]    = {  0,  0,  1 };
    float lookat[3] = {  0,  0,  0 };
    float up[3]     = {  0,  1,  0 };
    vx_layer_camera_lookat (layer, eye, lookat, up, 1);

    vx_code_output_stream_t *couts = vx_code_output_stream_create (128);
    couts->write_uint32 (couts, OP_LAYER_CAMERA);
    couts->write_uint32 (couts, vx_layer_id (layer));
    couts->write_uint32 (couts, OP_INTERFACE_MODE);
    couts->write_float  (couts, 2.5f);
    disp->send_codes (disp, couts->data, couts->pos);
    vx_code_output_stream_destroy (couts);
}
void process_buffer(vx_gtk_buffer_manager_t * man, vx_code_input_stream_t * cins)
{
    int world_id = cins->read_uint32(cins);
    const char * name = cins->read_str(cins);
    int draw_order = cins->read_uint32(cins);

    // find a matching layer:
    int update = 0;
    pthread_mutex_lock(&man->mutex);
    {
        layer_info_t * linfo = NULL;
        int layer_id = 0;
        zhash_iterator_t itr;
        zhash_iterator_init(man->layers, &itr);
        while(zhash_iterator_next(&itr, &layer_id, &linfo)) {
            if (linfo->world_id == world_id) {
                break;
            }
        }

        if (linfo == NULL) { // XXX Assert?
            pthread_mutex_unlock(&man->mutex);
            return;
        }

        // Now ensure there's a buffer_info_t in this layer.
        buffer_info_t * buffer = NULL;
        int success = zhash_get(linfo->buffers, &name, &buffer);

        // buffer doesn't exist yet?
        if (!success) {
            buffer = calloc(1, sizeof(buffer_info_t));
            buffer->layer_id = linfo->layer_id;
            buffer->name = strdup(name);
            buffer->enabled = 1;
            buffer->draw_order = draw_order;
            buffer->man = man;

            zhash_put(linfo->buffers, &buffer->name, &buffer, NULL, NULL);

            update = 1;
        }

        // draw order changed?
        if (success && draw_order != buffer->draw_order) {
            assert(buffer != NULL);
            buffer->draw_order = draw_order;

            update = 1;
        }
    }
    pthread_mutex_unlock(&man->mutex);

    if (update == 1)
        queue_update_view(man);
}
Example #5
0
// XXX make static
render_info_t * render_info_copy (render_info_t * rinfo)
{
    assert(rinfo != NULL);
    render_info_t * rinfo_copy = render_info_create();

    // copy a list of ints (ordered)
    for (int i = 0; i < zarray_size(rinfo->layers); i++) {
        layer_info_t * layer_info = NULL;
        zarray_get(rinfo->layers, i, &layer_info);
        zarray_add(rinfo_copy->layers, &layer_info);
    }

    // copy all the camera positions
    {
        zhash_iterator_t vit;
        uint32_t layer_id;
        vx_camera_pos_t *pos;
        zhash_iterator_init (rinfo->camera_positions, &vit);
        while (zhash_iterator_next (&vit, &layer_id, &pos)) {
            vx_camera_pos_t *pos_copy = malloc (sizeof(*pos_copy));
            memcpy(pos_copy, pos, sizeof(vx_camera_pos_t));
            zhash_put (rinfo_copy->camera_positions, &layer_id, &pos_copy, NULL, NULL);
        }
    }

    // copy each individual layer viewports
    {
        zhash_iterator_t itr;
        uint32_t layer_id;
        int *viewport;
        zhash_iterator_init (rinfo->layer_positions, &itr);
        while (zhash_iterator_next (&itr, &layer_id, &viewport)) {
            int *viewport_copy = malloc (4*sizeof(int));
            memcpy(viewport_copy, viewport, 4*sizeof(int));
            zhash_put (rinfo_copy->layer_positions, &layer_id, &viewport_copy, NULL, NULL);
        }
    }

    memcpy(rinfo_copy->viewport, rinfo->viewport, 4*sizeof(int));

    return rinfo_copy;
}
Example #6
0
// Add all elements in B to A
static void addAll(zhash_t * A, zhash_t  * B)
{
    zhash_iterator_t itr;
    zhash_iterator_init(B, &itr);
    uint64_t id = -1;
    void * value;
    while(zhash_iterator_next(&itr, &id, &value)) {
        if (!zhash_contains(A, &id))
            zhash_put(A, &id, &value, NULL, NULL);
    }
}
Example #7
0
File: vx_demo.c Project: DH-std/A3
static void display_started(vx_application_t * app, vx_display_t * disp)
{
    state_t * state = app->impl;

    vx_layer_t * layer = vx_layer_create(state->world);
    vx_layer_set_display(layer, disp);

    pthread_mutex_lock(&state->mutex);
    // store a reference to the world and layer that we associate with each vx_display_t
    zhash_put(state->layers, &disp, &layer, NULL, NULL);
    pthread_mutex_unlock(&state->mutex);
}
void
getopt_add_string (getopt_t *gopt, char sopt, const char *lname, const char *def, const char *help)
{
    char sname[2];
    sname[0] = sopt;
    sname[1] = 0;
    char *sname_ptr = (char*) &sname;

    if (strlen (lname) < 1) { // must have long name
        fprintf (stderr, "getopt_add_string(): must supply option name\n");
        exit (EXIT_FAILURE);
    }

    if (sopt == '-') { // short name cannot be '-' (no way to reference)
        fprintf (stderr, "getopt_add_string(): invalid option character: '%c'\n", sopt);
        exit (EXIT_FAILURE);
    }

    if (zhash_contains (gopt->lopts, &lname)) {
        fprintf (stderr, "getopt_add_string(): duplicate option name: --%s\n", lname);
        exit (EXIT_FAILURE);
    }

    if (sopt != '\0' && zhash_contains (gopt->sopts, &sname_ptr)) {
        fprintf (stderr, "getopt_add_string(): duplicate option: -%s ('%s')\n", sname, lname);
        exit (EXIT_FAILURE);
    }

    getopt_option_t *goo = calloc (1, sizeof(*goo));
    goo->sname = strdup (sname);
    goo->lname = strdup (lname);
    goo->svalue = strdup(def);
    goo->type = GOO_STRING_TYPE;
    goo->help = strdup (help);

    zhash_put (gopt->lopts, &goo->lname, &goo, NULL, NULL);
    zhash_put (gopt->sopts, &goo->sname, &goo, NULL, NULL);
    zarray_add (gopt->options, &goo);
}
void process_layer(vx_gtk_buffer_manager_t * man, vx_code_input_stream_t * cins)
{
    int layer_id = cins->read_uint32(cins);
    int world_id = cins->read_uint32(cins);
    int draw_order = cins->read_uint32(cins);
    /* int bg_color = cins->read_uint32(cins); */

    int update = 0;
    pthread_mutex_lock(&man->mutex);
    {
        layer_info_t * linfo = NULL;
        int success = zhash_get(man->layers, &layer_id, &linfo);

        if (!success) {
            linfo = calloc(1,sizeof(layer_info_t));
            linfo->layer_id = layer_id;
            linfo->world_id = world_id;
            linfo->buffers = zhash_create(sizeof(char*), sizeof(buffer_info_t*), zhash_str_hash, zhash_str_equals);

            zhash_put(man->layers, &layer_id, &linfo, NULL, NULL);
            update = 1;
        }

        if (success && draw_order != linfo->draw_order) {
            assert(linfo != NULL);
            linfo->draw_order = draw_order;

            update = 1;
        }
        assert(linfo->world_id == world_id);
    }
    pthread_mutex_unlock(&man->mutex);

    if (update == 1)
        queue_update_view(man);

}
Example #10
0
// Pass in a codes describing which resources are no longer in use. Decrement user counts,
// and return a list of all resources whos counts have reached zero, which therefore
// should be deleted from the display using a OP_DEALLOC_RESOURCES opcode
void vx_resc_manager_buffer_resources(vx_resc_manager_t * mgr, const uint8_t * data, int datalen)
{
    if (0) print_manager(mgr);

    vx_code_input_stream_t * cins = vx_code_input_stream_create(data, datalen);
    int code = cins->read_uint32(cins);
    assert(code == OP_BUFFER_RESOURCES);
    int worldID = cins->read_uint32(cins);
    char * name = strdup(cins->read_str(cins)); //freed when cur_resources is eventually removed from the buffer map
    int count = cins->read_uint32(cins);

    zhash_t * cur_resources = zhash_create(sizeof(uint64_t), sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals);
    vx_resc_t * vr = NULL;
    for (int i = 0; i < count; i++) {
        uint64_t id = cins->read_uint64(cins);
        zhash_put(cur_resources, &id, &vr, NULL, NULL);
    }
    assert(cins->pos == cins->len); // we've emptied the stream
    vx_code_input_stream_destroy(cins);

    // 1 Update our records
    zhash_t * worldBuffers = NULL;
    zhash_get(mgr->allLiveSets, &worldID, &worldBuffers);
    if (worldBuffers == NULL) {
        worldBuffers = zhash_create(sizeof(char*), sizeof(zhash_t*), zhash_str_hash, zhash_str_equals);
        zhash_put(mgr->allLiveSets, &worldID, &worldBuffers, NULL, NULL);
    }

    zhash_t * old_resources = NULL;
    char * old_name = NULL;
    zhash_put(worldBuffers, &name, &cur_resources, &old_name, &old_resources);
    free(old_name);

    // 2 Figure out which resources have become unused:
    if(old_resources != NULL) {
        removeAll(old_resources, cur_resources);

        zarray_t * dealloc = zarray_create(sizeof(uint64_t));

        // now 'old_resources' contains only the resources that are no longer referenced
        // iterate through each one, and see if there is a buffer somewhere that references it
        zhash_iterator_t prev_itr;
        zhash_iterator_init(old_resources, &prev_itr);
        uint64_t id = -1;
        vx_resc_t * vr = NULL;
        while(zhash_iterator_next(&prev_itr, &id, &vr)) {
            // Check all worlds
            zhash_iterator_t  world_itr;// gives us all worlds
            zhash_iterator_init(mgr->allLiveSets, &world_itr);
            uint32_t wIDl = -1;
            zhash_t * buffer_map = NULL;
            while(zhash_iterator_next(&world_itr, &wIDl, &buffer_map)) {
                zhash_iterator_t buffer_itr; // gives us all buffers
                zhash_iterator_init(buffer_map, &buffer_itr);
                char * bName = NULL;
                zhash_t * resc_map = NULL;
                while(zhash_iterator_next(&buffer_itr, &bName, &resc_map)) {
                    if (zhash_contains(resc_map, &id)) {
                        goto continue_outer_loop;
                    }
                }

            }

            // If none of the worlds have this resource, we need to flag removal
            zarray_add(dealloc, &id);

          continue_outer_loop:
            ;
        }


        // 3 Issue dealloc commands
        if (zarray_size(dealloc) > 0) {
            vx_code_output_stream_t * couts = vx_code_output_stream_create(512);
            couts->write_uint32(couts, OP_DEALLOC_RESOURCES);
            couts->write_uint32(couts, zarray_size(dealloc));
            for (int i = 0; i < zarray_size(dealloc); i++) {
                uint64_t id = 0;
                zarray_get(dealloc, i, &id);
                couts->write_uint64(couts, id);
            }

            mgr->disp->send_codes(mgr->disp, couts->data, couts->pos);

            vx_code_output_stream_destroy(couts);

            // Also remove the resources we deallocated from remoteResc
            for (int i = 0; i < zarray_size(dealloc); i++) {
                uint64_t id = 0;
                zarray_get(dealloc, i, &id);

                assert(zhash_contains(mgr->remoteResc, &id));
                zhash_remove(mgr->remoteResc, &id, NULL, NULL);
            }

        }
        zarray_destroy(dealloc);
        zhash_destroy(old_resources);

    }
    if (0) {
        print_manager(mgr);
        printf("\n\n");
    }
}
Example #11
0
// this loop tries to run at X fps, and issue render commands
static void * render_loop(void * foo)
{
    state_t * state = foo;
    if (verbose)printf("Starting render thread!\n");

    uint64_t render_count = 0;
    uint64_t last_mtime = vx_mtime();
    double avgDT = 1.0f/state->target_frame_rate;
    uint64_t avg_loop_us = 3000; // initial render time guess
    while (state->rendering) {
        int64_t sleeptime = (1000000 / state->target_frame_rate) - (int64_t) avg_loop_us;
        if (sleeptime > 0)
            usleep(sleeptime); // XXX fix to include render time

        // Diagnostic tracking
        uint64_t mtime_start = vx_mtime(); // XXX
        avgDT = avgDT*.9 + .1 * (mtime_start - last_mtime)/1000;
        last_mtime = mtime_start;
        render_count++;

        if (verbose) {
            if (render_count % 100 == 0)
                printf("Average render DT = %.3f FPS = %.3f avgloopus %"PRIu64" sleeptime = %"PRIi64"\n",
                       avgDT, 1.0/avgDT, avg_loop_us, sleeptime);
        }

        // prep the render data
        render_buffer_t rbuf;
        rbuf.state = state;
        rbuf.width = gtku_image_pane_get_width(state->imagePane);
        rbuf.height = gtku_image_pane_get_height(state->imagePane);
        if (rbuf.width == 0 && rbuf.height == 0)
            continue; // if the viewport is 0,0

        // smartly reuse, or reallocate the output pixel buffer when resizing occurs
        GdkPixbuf * pixbuf = state->pixbufs[state->cur_pb_idx];
        if (pixbuf == NULL || gdk_pixbuf_get_width(pixbuf) != rbuf.width || gdk_pixbuf_get_height(pixbuf) != rbuf.height) {
            if (pixbuf != NULL) {
                g_object_unref(pixbuf);
                free(state->pixdatas[state->cur_pb_idx]);
            }

            state->pixdatas[state->cur_pb_idx] = malloc(rbuf.width*rbuf.height*3); // can't stack allocate, can be too big (retina)
            pixbuf = gdk_pixbuf_new_from_data(state->pixdatas[state->cur_pb_idx], GDK_COLORSPACE_RGB, FALSE, 8,
                                              rbuf.width, rbuf.height, rbuf.width*3, NULL, NULL); // no destructor fn for pix data, handle manually
            state->pixbufs[state->cur_pb_idx] = pixbuf;
        }

        // second half of init:
        rbuf.out_buf = gdk_pixbuf_get_pixels(pixbuf);
        rbuf.format = GL_RGB;
        rbuf.rendered = 0;

        // 1 compute all the viewports
        render_info_t * rinfo = render_info_create();
        rinfo->viewport[0] = rinfo->viewport[1] = 0;
        rinfo->viewport[2] = rbuf.width;
        rinfo->viewport[3] = rbuf.height;

        {
            zhash_iterator_t itr;
            uint32_t layer_id = 0;
            layer_info_t * linfo = NULL;
            zhash_iterator_init(state->layer_info_map, &itr);
            while(zhash_iterator_next(&itr, &layer_id, &linfo)){
                zarray_add(rinfo->layers, &linfo);
            }
            zarray_sort(rinfo->layers, zvx_layer_info_compare);
        }

        zarray_t * fp = zarray_create(sizeof(matd_t*));

        matd_t *mm = matd_create(4,4); zarray_add(fp, &mm);
        matd_t *pm = matd_create(4,4); zarray_add(fp, &pm);

        pthread_mutex_lock(&state->mutex);
        for (int i = 0; i < zarray_size(rinfo->layers); i++) {
            layer_info_t *linfo = NULL;
            zarray_get(rinfo->layers, i, &linfo);

            int * viewport = vx_viewport_mgr_get_pos(linfo->vp_mgr, rinfo->viewport, mtime_start);
            vx_camera_pos_t *pos = default_cam_mgr_get_cam_pos(linfo->cam_mgr, viewport, mtime_start);

            // store viewport, pos
            zhash_put(rinfo->layer_positions, &linfo->layer_id, &viewport, NULL, NULL);
            zhash_put(rinfo->camera_positions, &linfo->layer_id, &pos, NULL, NULL);

            // feed the actual camera/projection matrix to the gl side
            vx_camera_pos_model_matrix(pos,mm->data);
            vx_camera_pos_projection_matrix(pos, pm->data);

            matd_t * pmmm = matd_multiply(pm,mm); zarray_add(fp, &pmmm);

            float pm16[16];
            vx_util_copy_floats(pmmm->data, pm16, 16);

            float eye3[16];
            vx_util_copy_floats(pos->eye, eye3, 3);

            vx_gl_renderer_set_layer_render_details(state->glrend, linfo->layer_id, viewport, pm16, eye3);
        }

        // 2 Render the data
        task_thread_schedule_blocking(gl_thread, render_task, &rbuf);

        render_info_t * old = state->last_render_info;
        state->last_render_info = rinfo;

        pthread_mutex_unlock(&state->mutex);


        // 3 if a render occurred, then swap gtk buffers
        if (rbuf.rendered) {

            // point to the correct buffer for the next render:
            state->cur_pb_idx = (state->cur_pb_idx +1 ) % 2;

            // flip y coordinate in place:
            vx_util_flipy(rbuf.width*3, rbuf.height, rbuf.out_buf);

            // swap the image's backing buffer
            g_object_ref(pixbuf); // XXX Since gtku always unrefs with each of these calls, increment accordingly
            gtku_image_pane_set_buffer(state->imagePane, pixbuf);
        }

        // 3.1 If a movie is in progress, also need to serialize the frame
        pthread_mutex_lock(&state->movie_mutex);
        if (state->movie_file != NULL) {

            int last_idx = (state->cur_pb_idx + 1) % 2;
            GdkPixbuf * pb = state->pixbufs[last_idx];

            movie_frame_t * movie_img = calloc(1, sizeof(movie_frame_t));
            movie_img->mtime = mtime_start;
            movie_img->width = gdk_pixbuf_get_width(pb);
            movie_img->height = gdk_pixbuf_get_height(pb);
            movie_img->stride = 3*movie_img->width;
            movie_img->buf = malloc(movie_img->stride*movie_img->height);
            memcpy(movie_img->buf, state->pixdatas[last_idx], movie_img->stride*movie_img->height);


            // Alloc in this thread, dealloc in movie thread
            zarray_add(state->movie_pending, & movie_img);

            pthread_cond_signal(&state->movie_cond);

        }
        pthread_mutex_unlock(&state->movie_mutex);


        // cleanup
        if (old)
            render_info_destroy(old);
        zarray_vmap(fp, matd_destroy);
        zarray_destroy(fp);


        uint64_t mtime_end = vx_mtime();
        avg_loop_us = (uint64_t)(.5*avg_loop_us + .5 * 1000 * (mtime_end - mtime_start));
    }
    if (verbose) printf("Render thread exiting\n");

    pthread_exit(NULL);

}
Example #12
0
zarray_t *apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im)
{
    ////////////////////////////////////////////////////////
    // step 1. threshold the image, creating the edge image.

    int w = im->width, h = im->height, s = im->stride;

    image_u8_t *threshim = threshold(td, im);
    assert(threshim->stride == s);

    image_u8_t *edgeim = image_u8_create(w, h);

    if (1) {
        image_u8_t *sumim = image_u8_create(w, h);

        // apply a horizontal sum kernel of width 3
        for (int y = 0; y < h; y++) {
            for (int x = 1; x+1 < w; x++) {

                sumim->buf[y*s + x] =
                    threshim->buf[y*s + x - 1] +
                    threshim->buf[y*s + x + 0] +
                    threshim->buf[y*s + x + 1];
            }
        }
        timeprofile_stamp(td->tp, "sumim");

        // deglitch
        if (td->qtp.deglitch) {
            for (int y = 1; y+1 < h; y++) {
                for (int x = 1; x+1 < w; x++) {
                    // edge: black pixel next to white pixel
                    if (threshim->buf[y*s + x] == 0 &&
                        sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] == 8) {
                        threshim->buf[y*s + x] = 1;
                        sumim->buf[y*s + x - 1]++;
                        sumim->buf[y*s + x + 0]++;
                        sumim->buf[y*s + x + 1]++;
                    }

                    if (threshim->buf[y*s + x] == 1 &&
                        sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] == 1) {
                        threshim->buf[y*s + x] = 0;
                        sumim->buf[y*s + x - 1]--;
                        sumim->buf[y*s + x + 0]--;
                        sumim->buf[y*s + x + 1]--;
                   }
                }
            }

            timeprofile_stamp(td->tp, "deglitch");
        }

        // apply a vertical sum kernel of width 3; check if any
        // over-threshold pixels are adjacent to an under-threshold
        // pixel.
        //
        // There are two types of edges: white pixels neighboring a
        // black pixel, and black pixels neighboring a white pixel. We
        // label these separately.  (Values 0xc0 and 0x3f are picked
        // such that they add to 255 (see below) and so that they can be
        // viewed as pixel intensities for visualization purposes.)
        //
        // symmetry of detection. We don't want to use JUST "black
        // near white" (or JUST "white near black"), because that
        // biases the detection towards one side of the edge. This
        // measurably reduces detection performance.
        //
        // On large tags, we could treat "neighbor" pixels the same
        // way. But on very small tags, there may be other edges very
        // near the tag edge. Since each of these edges is effectively
        // two pixels thick (the white pixel near the black pixel, and
        // the black pixel near the white pixel), it becomes likely
        // that these two nearby edges will actually touch.
        //
        // A partial solution to this problem is to define edges to be
        // adjacent white-near-black and black-near-white pixels.
        //

        for (int y = 1; y+1 < h; y++) {
            for (int x = 1; x+1 < w; x++) {
                if (threshim->buf[y*s + x] == 0) {
                    // edge: black pixel next to white pixel
                    if (sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] > 0)
                        edgeim->buf[y*s + x] = 0xc0;
                } else {
                    // edge: white pixel next to black pixel when both
                    // edge types are on, we get less bias towards one
                    // side of the edge.
                    if (sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] < 9)
                        edgeim->buf[y*s + x] = 0x3f;
                }
            }
        }

        if (td->debug) {
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
                    threshim->buf[y*s + x] *= 255;
                }
            }

            image_u8_write_pnm(threshim, "debug_threshold.pnm");
            image_u8_write_pnm(edgeim, "debug_edge.pnm");
//            image_u8_destroy(edgeim2);
        }

        image_u8_destroy(threshim);
        image_u8_destroy(sumim);
    }

    timeprofile_stamp(td->tp, "edges");

    ////////////////////////////////////////////////////////
    // step 2. find connected components.

    unionfind_t *uf = unionfind_create(w * h);

    for (int y = 1; y < h - 1; y++) {
        for (int x = 1; x < w -1; x++) {
            uint8_t v = edgeim->buf[y*s + x];
            if (v==0)
                continue;

            // (dx,dy) pairs for 8 connectivity:
            //          (REFERENCE) (1, 0)
            // (-1, 1)    (0, 1)    (1, 1)
            //
            // i.e., the minimum value of dx should be:
            //   y=0:   1
            //   y=1:  -1
            for (int dy = 0; dy <= 1; dy++) {
                for (int dx = 1-2*dy; dx <= 1; dx++) {
                    if (edgeim->buf[(y+dy)*s + (x+dx)] == v) {
                        unionfind_connect(uf, y*w + x, (y+dy)*w + x + dx);
                    }
                }
            }
        }
    }

    timeprofile_stamp(td->tp, "unionfind");

    zhash_t *clustermap = zhash_create(sizeof(uint64_t), sizeof(zarray_t*),
                                       zhash_uint64_hash, zhash_uint64_equals);

    for (int y = 1; y < h-1; y++) {
        for (int x = 1; x < w-1; x++) {

            uint8_t v0 = edgeim->buf[y*s + x];
            if (v0 == 0)
                continue;

            uint64_t rep0 = unionfind_get_representative(uf, y*w + x);

            // 8 connectivity. (4 neighbors to check).
//            for (int dy = 0; dy <= 1; dy++) {
//                for (int dx = 1-2*dy; dx <= 1; dx++) {

            // 4 connectivity. (2 neighbors to check)
            for (int n = 1; n <= 2; n++) {
                int dy = n & 1;
                int dx = (n & 2) >> 1;

                uint8_t v1 = edgeim->buf[(y+dy)*s + x + dx];
                if (v0 + v1 != 255)
                    continue;
                uint64_t rep1 = unionfind_get_representative(uf, (y+dy)*w + x+dx);

                uint64_t clusterid;
                if (rep0 < rep1)
                    clusterid = (rep1 << 32) + rep0;
                else
                    clusterid = (rep0 << 32) + rep1;

                zarray_t *cluster = NULL;
                if (!zhash_get(clustermap, &clusterid, &cluster)) {
                    cluster = zarray_create(sizeof(struct pt));
                    zhash_put(clustermap, &clusterid, &cluster, NULL, NULL);
                }

                // NB: We will add some points multiple times to a
                // given cluster.  I don't know an efficient way to
                // avoid that here; we remove them later on when we
                // sort points by pt_compare_theta.
                if (1) {
                    struct pt p = { .x = x, .y = y};
                    zarray_add(cluster, &p);
                }
                if (1) {
                    struct pt p = { .x = x+dx, .y = y+dy};
                    zarray_add(cluster, &p);
                }
            }
        }
    }

    // make segmentation image.
    if (td->debug) {
        image_u8_t *d = image_u8_create(w, h);
        assert(d->stride == s);

        uint8_t *colors = (uint8_t*) calloc(w*h, 1);

        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                uint32_t v = unionfind_get_representative(uf, y*w+x);
                uint32_t sz = unionfind_get_set_size(uf, y*w+x);
                if (sz < td->qtp.min_cluster_pixels)
                    continue;

                uint8_t color = colors[v];

                if (color == 0) {
                    const int bias = 20;
                    color = bias + (random() % (255-bias));
                    colors[v] = color;
                }

                float mix = 0.7;
                mix = 1.0;
                d->buf[y*d->stride + x] = mix*color + (1-mix)*im->buf[y*im->stride + x];
            }
        }

        free(colors);

        image_u8_write_pnm(d, "debug_segmentation.pnm");
        image_u8_destroy(d);
    }

    timeprofile_stamp(td->tp, "make clusters");


    ////////////////////////////////////////////////////////
    // step 3. process each connected component.

    zarray_t *clusters = zhash_values(clustermap);
    zhash_destroy(clustermap);

    zarray_t *quads = zarray_create(sizeof(struct quad));

    int sz = zarray_size(clusters);
    int chunksize = 1 + sz / (APRILTAG_TASKS_PER_THREAD_TARGET * td->nthreads);
    struct quad_task tasks[sz / chunksize + 1];

    int ntasks = 0;
    for (int i = 0; i < sz; i += chunksize) {
        tasks[ntasks].td = td;
        tasks[ntasks].cidx0 = i;
        tasks[ntasks].cidx1 = imin(sz, i + chunksize);
        tasks[ntasks].h = h;
        tasks[ntasks].w = w;
        tasks[ntasks].quads = quads;
        tasks[ntasks].clusters = clusters;
        tasks[ntasks].im = im;

        workerpool_add_task(td->wp, do_quad_task, &tasks[ntasks]);
        ntasks++;
    }

    workerpool_run(td->wp);

    timeprofile_stamp(td->tp, "fit quads to clusters");

    if (td->debug) {
        FILE *f = fopen("debug_lines.ps", "w");
        fprintf(f, "%%!PS\n\n");

        image_u8_t *im2 = image_u8_copy(im);
        image_u8_darken(im2);
        image_u8_darken(im2);

        // assume letter, which is 612x792 points.
        double scale = fmin(612.0/im->width, 792.0/im2->height);
        fprintf(f, "%.15f %.15f scale\n", scale, scale);
        fprintf(f, "0 %d translate\n", im2->height);
        fprintf(f, "1 -1 scale\n");

        postscript_image(f, im);

        for (int i = 0; i < zarray_size(quads); i++) {
            struct quad *q;
            zarray_get_volatile(quads, i, &q);

            float rgb[3];
            int bias = 100;

            for (int i = 0; i < 3; i++)
                rgb[i] = bias + (random() % (255-bias));

            fprintf(f, "%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
            fprintf(f, "%.15f %.15f moveto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto stroke\n",
                    q->p[0][0], q->p[0][1],
                    q->p[1][0], q->p[1][1],
                    q->p[2][0], q->p[2][1],
                    q->p[3][0], q->p[3][1],
                    q->p[0][0], q->p[0][1]);
        }

        fclose(f);
    }

//        printf("  %d %d %d %d\n", indices[0], indices[1], indices[2], indices[3]);

/*
        if (td->debug) {
            for (int i = 0; i < 4; i++) {
            int i0 = indices[i];
                int i1 = indices[(i+1)&3];

                if (i1 < i0)
                    i1 += zarray_size(cluster);

                for (int j = i0; j <= i1; j++) {
                    struct pt *p;
                    zarray_get_volatile(cluster, j % zarray_size(cluster), &p);

                    edgeim->buf[p->y*edgeim->stride + p->x] = 30+64*i;
                }
            }
            } */

    unionfind_destroy(uf);

    for (int i = 0; i < zarray_size(clusters); i++) {
        zarray_t *cluster;
        zarray_get(clusters, i, &cluster);
        zarray_destroy(cluster);
    }

    zarray_destroy(clusters);

    image_u8_destroy(edgeim);

    return quads;
}
Example #13
0
void hsv_find_balls_blob_detector(image_u32_t* im, frame_t frame, metrics_t met, zarray_t* blobs_out)
{
    assert(frame.xy0.x < frame.xy1.x && frame.xy0.y < frame.xy1.y);
    assert(frame.xy0.x >= 0 && frame.xy0.y >= 0 && frame.xy1.x < im->width && frame.xy1.y < im->height);
    assert(frame.ex0.x < frame.ex1.x && frame.ex0.y < frame.ex1.y);
    assert(frame.ex0.x >= 0 && frame.ex0.y >= 0 && frame.ex1.x < im->width && frame.ex1.y < im->height);

    // Int to node
    zhash_t* node_map = zhash_create(sizeof(uint32_t), sizeof(node_t*),
            zhash_uint32_hash, zhash_uint32_equals);

    for(int i = frame.xy0.y; i < frame.xy1.y; i++) {
        for(int j = frame.xy0.x; j < frame.xy1.x; j++) {
            if((i < frame.ex0.y || i > frame.ex1.y) || (j < frame.ex0.x || j > frame.ex1.x)) {

                uint32_t idx_im = i * im->stride + j; // Indframe.ex relative to image

                // Pixel color data
                uint32_t abgr = im->buf[idx_im];
                hsv_t hsv = {0,0,0};
                rgb_to_hsv(abgr, &hsv);
                hsv_t error = {fabs(hsv.hue - met.hsv.hue), 
                                fabs(hsv.sat - met.hsv.sat), 
                                fabs(hsv.val - met.hsv.val)};

                // 'Acceptable'
                 if((error.hue < met.error.hue) && 
                    (error.sat < met.error.sat) && 
                    (error.val < met.error.val)) 
                 {
                    // Create new node, set itself up as a parent
                    node_t* n = calloc(1, sizeof(node_t));
                    n->id = idx_im;
                    n->parent_id = idx_im;
                    n->parent_node = n;
                    n->num_children = 0;

                    node_t* tmp_node;
                    uint32_t tmp_idx;

                    // Add node to node map
                    if(zhash_put(node_map, &idx_im, &n, &tmp_idx, &tmp_node)==1) 
                    {
                        assert(0);
                    }

                    //Check if apart of another blob, or starting a new blob 
                    // if apart of another, point to the parent, if a new blob, point to self 
                    //Check neighbours
                    if(!met.lines) {    // only check this if don't want lines for tape detection
                        if(j > frame.xy0.x) {
                            tmp_idx = idx_im - 1; // is Left neighbour similar color 
                            if(zhash_get(node_map, &tmp_idx, &tmp_node) == 1) {
                                node_t* neighbour = tmp_node;
                                connect(n, neighbour);                    
                            }
                        }
                    }
                    if(i > frame.xy0.y) { 
                        tmp_idx = idx_im - im->stride; // is Bottom neighbor similar color
                        if(tmp_idx > 0 && zhash_get(node_map, &tmp_idx, &tmp_node) == 1) {
                            node_t* neighbour = tmp_node;
                            connect(neighbour,n);                    
                        }
                    }
                }
            }
        }
    }


    //count number of children for each parent, go through node_map
    // if a node is not a parent, add 1 to it's parent->num_children and delete from hash
    // if is a parent do nothing
    zarray_t* vals = zhash_values(node_map);
    for(int i = 0; i < zarray_size(vals); i++) {
        node_t* node;
        zarray_get(vals, i, &node);
        resolve_r(node);

        if(node->parent_id != node->id) {
            node->parent_node->num_children++;
            // key should exist, if it doesn't find out why
            assert(zhash_remove(node_map, &node->id, NULL, NULL));
        }
    }

    // search parent only hash and add to blobs out conditionally
    vals = zhash_values(node_map);
    for(int i = 0; i < zarray_size(vals); i++) {
        node_t* node;
        zarray_get(vals, i, &node);
        if(node->num_children > met.min_size) {
            loc_t pos;
            pos.x = node->parent_id%im->stride;
            pos.y = node->parent_id/im->stride;
            zarray_add(blobs_out, &pos);
            // printf("parent %d\n", node->id);
        }
    }
    zarray_destroy(vals);
    zhash_vmap_values(node_map, free);
    zhash_destroy(node_map);
}
Example #14
0
static void display_started(vx_application_t * app, vx_display_t * disp)
{
    state_t * state = app->impl;

    {
        vx_layer_t * layer = vx_layer_create(state->world);
        vx_layer_set_display(layer, disp);
        //vx_layer_camera_op(layer, OP_PROJ_ORTHO);

        if (1) {
            float view_rel[] = {0.0, 0.0, 1.0, 1.0};
            vx_layer_set_viewport_rel(layer, view_rel);
        }

        if (1) {
            float eye3[] = {CAM_RADIUS,0,45.0f};
            float lookat3[] = {CAM_RADIUS,0,0.0f};
            float up3[] = {0,1,0};
            vx_layer_camera_lookat(layer, eye3, lookat3, up3, 0);
        }

        if (1) {
            float xy0[] = {-10,-10};
            float xy1[] = {10,10};
            vx_layer_camera_fit2D(layer, xy0, xy1, 0);
        }


        pthread_mutex_lock(&state->mutex);
        // store a reference to the world and layer that we associate with each vx_display_t
        zhash_put(state->layers, &disp, &layer, NULL, NULL);
        pthread_mutex_unlock(&state->mutex);

        // must redraw after each new display connects

        draw(state, state->world);
    }

    {
        vx_layer_t * layer = vx_layer_create(state->world2);
        vx_layer_set_display(layer, disp);
        vx_layer_camera_op(layer, OP_PROJ_ORTHO);

        {
            vx_layer_set_viewport_abs(layer, OP_ANCHOR_TOP_RIGHT, 100, 100);
        }

        {
            float eye3[] = {10.0f,10.0f,100.0f};
            float lookat3[] = {10.0f,10.0f,0.0f};
            float up3[] = {0,1,0};
            vx_layer_camera_lookat(layer, eye3, lookat3, up3, 0);
        }

        {
            float xy0[] = {-10,-10};
            float xy1[] = {10,10};
            vx_layer_camera_fit2D(layer, xy0, xy1, 0);
        }

        vx_layer_add_event_handler(layer, &state->veh);
        vx_layer_add_camera_listener(layer, &state->cl);


        /*
        pthread_mutex_lock(&state->mutex);
        // store a reference to the world and layer that we associate with each vx_display_t
        zhash_put(state->layers, &disp, &layer, NULL, NULL);
        pthread_mutex_unlock(&state->mutex);
        */

        // must redraw after each new display connects

        draw(state, state->world2);
    }


    if (0) {
        vx_layer_t * layer = vx_layer_create(state->world3);
        vx_layer_set_display(layer, disp);
        vx_layer_set_background_color(layer, vx_green);

        // Manually send the codes for animating a layer (not in
        // vx_layer_api yet):

        {
            float viewport[] = {0, 0.5, 0.5, 0.5};

            vx_code_output_stream_t * couts = vx_code_output_stream_create(128);
            couts->write_uint32(couts, OP_LAYER_VIEWPORT_REL);
            couts->write_uint32(couts, vx_layer_id(layer));
            for (int i = 0; i < 4; i++)
                couts->write_float(couts, viewport[i]);
            couts->write_uint32(couts, 2000); // animate over 2 seconds

            disp->send_codes(disp, couts->data, couts->pos);

            vx_code_output_stream_destroy(couts);
        }

        draw(state, state->world3); // XXX Why is this required to get
        // the layer to show up?
    }


}
Example #15
0
// returns a hash <char*, material_t>, where keys and values are owned
// by the map, so be sure to free strings and dec ref the styles
static zhash_t * load_materials(const char * mtl_filename)
{
    FILE * fp_mtl = fopen(mtl_filename, "r");
    if (fp_mtl == NULL)
        return NULL;

    #define LNSZ 1024
    char line_buffer[LNSZ];

    // store materials by value
    zhash_t * mat_map = zhash_create(sizeof(char*), sizeof(material_t), zhash_str_hash, zhash_str_equals);

    char cur_name[LNSZ];

    material_t cur_material;
    memset(&cur_material,0, sizeof(cur_material));
    cur_material.illum = -1;

    // We commit to reading the
    while (1) {
        int eof = fgets(line_buffer, LNSZ, fp_mtl) == NULL;

        char * line = str_trim(line_buffer);

        // If possible, commit the old material
        if (str_starts_with(line, "newmtl") || eof) {
            if (cur_material.illum >= 0) {

                char * key = strdup(cur_name);

                char * oldkey = NULL;
                material_t oldmat;
                zhash_put(mat_map, &key, &cur_material, &oldkey, & oldmat);

                assert(oldkey == NULL);
                assert(cur_material.illum <= 2 && "can't handle anything higher than illum=2");
            }
        }

        if (eof)
            break;

        if (str_starts_with(line, "#") || strlen(line) == 0 || !strcmp(line, "\r"))
            continue;

        if (str_starts_with(line, "newmtl")) {
            sscanf(line, "newmtl %s", cur_name);
        } else if (str_starts_with(line, "Ns")) {
            sscanf(line, "Ns %f", &cur_material.Ns);
        } else if (str_starts_with(line, "Ni")) {
            sscanf(line, "Ni %f", &cur_material.Ni);
        } else if (str_starts_with(line, "d") || str_starts_with(line, "Tr")) {
            sscanf(line, "%*s %f", &cur_material.d);
        } else if (str_starts_with(line, "Tr")) {
            sscanf(line, "Tr %f", &cur_material.Tr);
        } else if (str_starts_with(line, "Tf")) {
            sscanf(line, "Tf %f %f %f", &cur_material.Tf[0],&cur_material.Tf[1],&cur_material.Tf[2]);
        }else if (str_starts_with(line, "illum")) {
            sscanf(line, "illum %d", &cur_material.illum);
        } else if (str_starts_with(line, "Ka")) {
            sscanf(line, "Ka %f %f %f", &cur_material.Ka[0],&cur_material.Ka[1],&cur_material.Ka[2]);
        } else if (str_starts_with(line, "Kd")) {
            sscanf(line, "Kd %f %f %f", &cur_material.Kd[0],&cur_material.Kd[1],&cur_material.Kd[2]);
        } else if (str_starts_with(line, "Ks")) {
            sscanf(line, "Ks %f %f %f", &cur_material.Ks[0],&cur_material.Ks[1],&cur_material.Ks[2]);
        } else if (str_starts_with(line, "Ke")) {
            sscanf(line, "Ke %f %f %f", &cur_material.Ke[0],&cur_material.Ke[1],&cur_material.Ke[2]);
        } else {
            printf("Did not parse: %s\n", line);

            for (int i = 0; i < strlen(line); i++) {
                printf("0x%x ", (int)line[i]);
            }
            printf("\n");
        }
    }

    fclose(fp_mtl);
    return mat_map;
}