// Tests ImageBuf construction from application buffer
void ImageBuf_test_appbuffer ()
{
    const int WIDTH = 8;
    const int HEIGHT = 8;
    const int CHANNELS = 1;
    static float buf[HEIGHT][WIDTH] = {
        { 0, 0, 0, 0, 1, 0, 0, 0 }, 
        { 0, 0, 0, 1, 0, 1, 0, 0 }, 
        { 0, 0, 1, 0, 0, 0, 1, 0 }, 
        { 0, 1, 0, 0, 0, 0, 0, 1 }, 
        { 0, 0, 1, 0, 0, 0, 1, 0 }, 
        { 0, 0, 0, 1, 0, 1, 0, 0 }, 
        { 0, 0, 0, 0, 1, 0, 0, 0 }, 
        { 0, 0, 0, 0, 0, 0, 0, 0 }
    };
    ImageSpec spec (WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT);
    ImageBuf A (spec, buf);

    // Make sure A now points to the buffer
    OIIO_CHECK_EQUAL ((void *)A.pixeladdr (0, 0, 0), (void *)buf);

    // write it
    A.write ("A.tif");

    // Read it back and make sure it matches the original
    ImageBuf B ("A.tif");
    for (int y = 0;  y < HEIGHT;  ++y)
        for (int x = 0;  x < WIDTH;  ++x)
            OIIO_CHECK_EQUAL (A.getchannel (x, y, 0, 0),
                              B.getchannel (x, y, 0, 0));
}
Beispiel #2
0
void
test_compute ()
{
    double time;

    ROI roi (0, xres, 0, yres, 0, 1, 0, channels);

    std::cout << "Test straightforward as 1D array of float: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);
    // imgR.write ("ref.exr");

    std::cout << "Test array iterated like an image: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays_like_image, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test array iterated like an image, multithreaded: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays_like_image_multithread_wrapper, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test array as 1D, using SIMD: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays_simd4, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test array iterated like an image, using SIMD: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays_like_image_simd, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test array iterated like an image, using SIMD, multithreaded: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_arrays_like_image_simd_multithread_wrapper, roi), ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test ImageBufAlgo::mad 1 thread: ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_IBA, roi, 1),
                       ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);

    std::cout << "Test ImageBufAlgo::mad multi-thread " << numthreads << ": ";
    ImageBufAlgo::zero (imgR);
    time = time_trial (std::bind (test_IBA, roi, numthreads),
                       ntrials, iterations) / iterations;
    std::cout << Strutil::format ("%.1f Mvals/sec", (size/1.0e6)/time) << std::endl;
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,0), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,1), 0.25, 0.001);
    OIIO_CHECK_EQUAL_THRESH (imgR.getchannel(xres/2,yres/2,0,2), 0.50, 0.001);
}
Beispiel #3
0
void
test_compute()
{
    Benchmarker bench;
    bench.iterations(iterations);
    bench.trials(ntrials);
    bench.work(xres * yres * channels);
    bench.units(Benchmarker::Unit::ms);

    ROI roi(0, xres, 0, yres, 0, 1, 0, channels);

    ImageBufAlgo::zero(imgR);
    bench("1D array loop", test_arrays, roi);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);
    // imgR.write ("ref.exr");

    ImageBufAlgo::zero(imgR);
    bench("iterated as image", test_arrays_like_image, roi);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("iterated as image, threaded",
          [&]() { ImageBufAlgo::parallel_image(roi, test_arrays_like_image); });
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("1D array loop, SIMD", test_arrays_simd4, roi);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("iterated as image, SIMD", test_arrays_like_image_simd, roi);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("iterated as image, SIMD, threaded", [&]() {
        ImageBufAlgo::parallel_image(roi, test_arrays_like_image_simd);
    });
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("IBA::mad 1 thread", test_IBA, roi, 1);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);

    ImageBufAlgo::zero(imgR);
    bench("IBA::mad threaded", test_IBA, roi, numthreads);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25,
                            0.001);
    OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50,
                            0.001);
}
Beispiel #4
0
int
ImageBufAlgo::compare_Yee (const ImageBuf &img0, const ImageBuf &img1,
                           CompareResults &result,
                           float luminance, float fov,
                           ROI roi, int nthreads)
{
    if (! roi.defined())
        roi = roi_union (get_roi(img0.spec()), get_roi(img1.spec()));
    roi.chend = std::max (roi.chend, roi.chbegin+3);  // max of 3 channels

    result.maxerror = 0;
    result.maxx=0, result.maxy=0, result.maxz=0, result.maxc=0;
    result.nfail = 0, result.nwarn = 0;

    int nscanlines = roi.height() * roi.depth();

    bool luminanceOnly = false;

    // assuming colorspaces are in Adobe RGB (1998), convert to LAB

    // paste() to copy of up to 3 channels, converting to float, and
    // ending up with a 0-origin image.  End up with an LAB image in
    // aLAB, and a luminance image in aLum.
    ImageSpec spec (roi.width(), roi.height(), 3 /*chans*/, TypeDesc::FLOAT);
    ImageBuf aLAB (spec);
    ImageBufAlgo::paste (aLAB, 0, 0, 0, 0, img0, roi, nthreads);
    AdobeRGBToXYZ (aLAB, ROI::All(), nthreads);  // contains XYZ now
    ImageBuf aLum;
    int channelorder[] = { 1 };  // channel to copy
    ImageBufAlgo::channels (aLum, aLAB, 1, channelorder);
    ImageBufAlgo::mul (aLum, aLum, luminance, ROI::All(), nthreads);
    XYZToLAB (aLAB, ROI::All(), nthreads);  // now it's LAB

    // Same thing for img1/bLAB/bLum
    ImageBuf bLAB (spec);
    ImageBufAlgo::paste (bLAB, 0, 0, 0, 0, img1, roi, nthreads);
    AdobeRGBToXYZ (bLAB, ROI::All(), nthreads);  // contains XYZ now
    ImageBuf bLum;
    ImageBufAlgo::channels (bLum, bLAB, 1, channelorder);
    ImageBufAlgo::mul (bLum, bLum, luminance, ROI::All(), nthreads);
    XYZToLAB (bLAB, ROI::All(), nthreads);  // now it's LAB

    // Construct Gaussian pyramids (not really pyramids, because they all
    // have the same resolution, but really just a bunch of successively
    // more blurred images).
    GaussianPyramid la (aLum);
    GaussianPyramid lb (bLum);

    float num_one_degree_pixels = (float) (2 * tan(fov * 0.5 * M_PI / 180) * 180 / M_PI);
    float pixels_per_degree = roi.width() / num_one_degree_pixels;

    unsigned int adaptation_level = 0;
    for (int i = 0, npixels = 1;
             i < PYRAMID_MAX_LEVELS && npixels <= num_one_degree_pixels;
             ++i, npixels *= 2) 
        adaptation_level = i;

    float cpd[PYRAMID_MAX_LEVELS];
    cpd[0] = 0.5f * pixels_per_degree;
    for (int i = 1;  i < PYRAMID_MAX_LEVELS;  ++i)
        cpd[i] = 0.5f * cpd[i - 1];
    float csf_max = contrast_sensitivity (3.248f, 100.0f);

    float F_freq[PYRAMID_MAX_LEVELS - 2];
    for (int i = 0; i < PYRAMID_MAX_LEVELS - 2;  ++i)
        F_freq[i] = csf_max / contrast_sensitivity (cpd[i], 100.0f);

    for (int y = 0; y < nscanlines;  ++y) {
        for (int x = 0;  x < roi.width();  ++x) {
            float contrast[PYRAMID_MAX_LEVELS - 2];
            float sum_contrast = 0;
            for (int i = 0; i < PYRAMID_MAX_LEVELS - 2; i++) {
                float n1 = fabsf (la.value(x,y,i) - la.value(x,y,i+1));
                float n2 = fabsf (lb.value(x,y,i) - lb.value(x,y,i+1));
                float numerator = std::max (n1, n2);
                float d1 = fabsf (la.value(x,y,i+2));
                float d2 = fabsf (lb.value(x,y,i+2));
                float denominator = std::max (std::max (d1, d2), 1.0e-5f);
                contrast[i] = numerator / denominator;
                sum_contrast += contrast[i];
            }
            if (sum_contrast < 1e-5)
                sum_contrast = 1e-5f;
            float F_mask[PYRAMID_MAX_LEVELS - 2];
            float adapt = la.value(x,y,adaptation_level) + lb.value(x,y,adaptation_level);
            adapt *= 0.5f;
            if (adapt < 1e-5)
                adapt = 1e-5f;
            for (int i = 0; i < PYRAMID_MAX_LEVELS - 2; i++)
                F_mask[i] = mask(contrast[i] * contrast_sensitivity(cpd[i], adapt)); 
            float factor = 0;
            for (int i = 0; i < PYRAMID_MAX_LEVELS - 2; i++)
                factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
            factor = Imath::clamp (factor, 1.0f, 10.0f);
            float delta = fabsf (la.value(x,y,0) - lb.value(x,y,0));
            bool pass = true;
            // pure luminance test
            delta /= tvi(adapt);
            if (delta > factor) {
                pass = false;
            } else if (! luminanceOnly) {
                // CIE delta E test with modifications
                float color_scale = 1.0f;
                // ramp down the color test in scotopic regions
                if (adapt < 10.0f) {
                    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
                    color_scale = color_scale * color_scale;
                }
                float da = aLAB.getchannel(x,y,0,1) - bLAB.getchannel(x,y,0,1);  // diff in A
                float db = aLAB.getchannel(x,y,0,2) - bLAB.getchannel(x,y,0,2);  // diff in B
                da = da * da;
                db = db * db;
                delta = (da + db) * color_scale;
                if (delta > factor)
                    pass = false;
            }
            if (!pass) {
                ++result.nfail;
                if (factor > result.maxerror) {
                    result.maxerror = factor;
                    result.maxx = x;
                    result.maxy = y;
//                    result.maxz = z;
                }
            }
        }
    }

    return result.nfail;
}
Beispiel #5
0
bool
ImageBufAlgo::deepen (ImageBuf &dst, const ImageBuf &src, float zvalue,
                      ROI roi, int nthreads)
{
    if (src.deep()) {
        // For some reason, we were asked to deepen an already-deep image.
        // So just copy it.
        return dst.copy (src);
        // FIXME: once paste works for deep files, this should really be
        // return paste (dst, roi.xbegin, roi.ybegin, roi.zbegin, roi.chbegin,
        //               src, roi, nthreads);
    }

    // Construct an ideal spec for dst, which is like src but deep.
    const ImageSpec &srcspec (src.spec());
    int nc = srcspec.nchannels;
    int zback_channel = -1;
    ImageSpec force_spec = srcspec;
    force_spec.deep = true;
    force_spec.set_format (TypeDesc::FLOAT);
    force_spec.channelformats.clear();
    for (int c = 0; c < nc; ++c) {
        if (force_spec.channelnames[c] == "Z")
            force_spec.z_channel = c;
        else if (force_spec.channelnames[c] == "Zback")
            zback_channel = c;
    }
    bool add_z_channel = (force_spec.z_channel < 0);
    if (add_z_channel) {
        // No z channel? Make one.
        force_spec.z_channel = force_spec.nchannels++;
        force_spec.channelnames.push_back ("Z");
    }

    if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP))
        return false;
    if (! dst.deep()) {
        dst.error ("Cannot deepen to a flat image");
        return false;
    }

    float *pixel = OIIO_ALLOCA (float, nc);

    // First, figure out which pixels get a sample and which do not
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        bool has_sample = false;
        src.getpixel (x, y, z, pixel);
        for (int c = 0; c < nc; ++c)
            if (c != force_spec.z_channel && c != zback_channel
                  && pixel[c] != 0.0f) {
                has_sample = true;
                break;
            }
        if (! has_sample && ! add_z_channel)
            for (int c = 0; c < nc; ++c)
                if ((c == force_spec.z_channel || c == zback_channel)
                    && (pixel[c] != 0.0f && pixel[c] < 1e30)) {
                    has_sample = true;
                    break;
                }
        if (has_sample)
            dst.set_deep_samples (x, y, z, 1);
    }

    dst.deep_alloc ();

    // Now actually set the values
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        if (dst.deep_samples (x, y, z) == 0)
            continue;
        for (int c = 0; c < nc; ++c)
            dst.set_deep_value (x, y, z, c, 0 /*sample*/,
                                src.getchannel (x, y, z, c));
        if (add_z_channel)
            dst.set_deep_value (x, y, z, nc, 0, zvalue);
    }

    bool ok = true;
    // FIXME -- the above doesn't split into threads. Someday, it should
    // be refactored like this:
    // OIIO_DISPATCH_COMMON_TYPES2 (ok, "deepen", deepen_,
    //                              dst.spec().format, srcspec.format,
    //                              dst, src, add_z_channel, z, roi, nthreads);
    return ok;
}