Beispiel #1
0
static void
fix_latl_edges (ImageBuf &buf)
{
    ASSERT (envlatlmode && "only call fix_latl_edges for latlong maps");
    int n = buf.nchannels();
    float *left = ALLOCA (float, n);
    float *right = ALLOCA (float, n);

    // Make the whole first and last row be solid, since they are exactly
    // on the pole
    float wscale = 1.0f / (buf.spec().width);
    for (int j = 0;  j <= 1;  ++j) {
        int y = (j==0) ? buf.ybegin() : buf.yend()-1;
        // use left for the sum, right for each new pixel
        for (int c = 0;  c < n;  ++c)
            left[c] = 0.0f;
        for (int x = buf.xbegin();  x < buf.xend();  ++x) {
            buf.getpixel (x, y, right);
            for (int c = 0;  c < n;  ++c)
                left[c] += right[c];
        }
        for (int c = 0;  c < n;  ++c)
            left[c] += right[c];
        for (int c = 0;  c < n;  ++c)
            left[c] *= wscale;
        for (int x = buf.xbegin();  x < buf.xend();  ++x)
            buf.setpixel (x, y, left);
    }

    // Make the left and right match, since they are both right on the
    // prime meridian.
    for (int y = buf.ybegin();  y < buf.yend();  ++y) {
        buf.getpixel (buf.xbegin(), y, left);
        buf.getpixel (buf.xend()-1, y, right);
        for (int c = 0;  c < n;  ++c)
            left[c] = 0.5f * left[c] + 0.5f * right[c];
        buf.setpixel (buf.xbegin(), y, left);
        buf.setpixel (buf.xend()-1, y, left);
    }
}
Beispiel #2
0
void
ImageBuf::copy_from (const ImageBuf &src)
{
    if (this == &src)
        return;
    ASSERT (m_spec.width == src.m_spec.width &&
            m_spec.height == src.m_spec.height &&
            m_spec.depth == src.m_spec.depth &&
            m_spec.nchannels == src.m_spec.nchannels);
    realloc ();
    if (m_spec.deep)
        m_deepdata = src.m_deepdata;
    else
        src.get_pixels (src.xbegin(), src.xend(), src.ybegin(), src.yend(),
                        src.zbegin(), src.zend(), m_spec.format, m_localpixels);
}
// DEPRECATED version
bool
ImageBufAlgo::add (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B,
                   int options)
{
    // Sanity checks
    
    // dst must be distinct from A and B
    if ((const void *)&A == (const void *)&dst ||
        (const void *)&B == (const void *)&dst) {
        dst.error ("destination image must be distinct from source");
        return false;
    }
    
    // all three images must have the same number of channels
    if (A.spec().nchannels != B.spec().nchannels) {
        dst.error ("channel number mismatch: %d vs. %d", 
                   A.spec().nchannels, B.spec().nchannels);
        return false;
    }
    
    // If dst has not already been allocated, set it to the right size,
    // make it unconditinally float
    if (! dst.pixels_valid()) {
        ImageSpec dstspec = A.spec();
        dstspec.set_format (TypeDesc::TypeFloat);
        dst.alloc (dstspec);
    }
    // Clear dst pixels if instructed to do so
    if (options & ADD_CLEAR_DST) {
        zero (dst);
    }
      
    ASSERT (A.spec().format == TypeDesc::FLOAT &&
            B.spec().format == TypeDesc::FLOAT &&
            dst.spec().format == TypeDesc::FLOAT);
    
    ImageBuf::ConstIterator<float,float> a (A);
    ImageBuf::ConstIterator<float,float> b (B);
    ImageBuf::Iterator<float> d (dst);
    int nchannels = A.nchannels();
    // Loop over all pixels in A
    for ( ; a.valid();  ++a) {  
        // Point the iterators for B and dst to the corresponding pixel
        if (options & ADD_RETAIN_WINDOWS) {
            b.pos (a.x(), a.y());
        } else {
            // ADD_ALIGN_WINDOWS: make B line up with A
            b.pos (a.x()-A.xbegin()+B.xbegin(), a.y()-A.ybegin()+B.ybegin());
        }
        d.pos (a.x(), b.y());
        
        if (! b.valid() || ! d.valid())
            continue;   // Skip pixels that don't align
        
        // Add the pixel
        for (int c = 0;  c < nchannels;  ++c)
              d[c] = a[c] + b[c];
    }
    
    return true;
}
Beispiel #4
0
int main (int argc, char *argv[])
{
    // Arguments
    if(argc != 3)
    {
        std::cerr << "mkthumbnail usage : mkthumbnail <input> <output>" << std::endl;
        return EXIT_FAILURE;
    }
    
    std::string inputname=argv[1];
    std::string outputname=argv[2];
	std::string colortransfer_to = "sRGB";
	std::string colortransfer_from = "sRGB";
    
    // Colorspace selection
    if(extensionIs(inputname, "exr") )
    {
       colortransfer_from="Linear"; 
    } 
    else if(extensionIs(inputname, "dpx"))
    {
       colortransfer_from="KodakLog"; 
    }
    else
    {
        colortransfer_from="sRGB"; 
    }

    bool ok = true;
    
    ImageBuf in;
    if (! read_input (inputname, in)) 
    {
        std::cerr << "mkthumbnail: read error: " << in.geterror() << "\n";
        return EXIT_FAILURE;
    }
    
    ColorTransfer *from_func = ColorTransfer::create (colortransfer_from + "_to_linear");
    if (from_func == NULL) {
        std::cerr << "mkthumbnail: --colorspace needs a 'colorspace' of "
            << "Linear, Gamma, sRGB, AdobeRGB, Rec709 or KodakLog\n";
        return EXIT_FAILURE;
    }

    ColorTransfer *to_func = ColorTransfer::create (std::string("linear_to_") + colortransfer_to);
    if (to_func == NULL) {
        std::cerr << "mkthumbnail: --transfer needs a 'colorspace' of "
            << "Linear, Gamma, sRGB, AdobeRGB, Rec709 or KodakLog\n";
        return EXIT_FAILURE;
    }
    std::cout << "Converting [" << colortransfer_from << "] " << inputname 
        << " to [" << colortransfer_to << "] " << outputname << "\n";
    
    //
    ImageBuf linear;
    ImageBuf outtmp;
    ImageBufAlgo::colortransfer (linear, in, from_func);
    ImageBufAlgo::colortransfer (outtmp, linear, to_func);
    std::cout << "finished color transfer\n";
    
  
    // Pixel aspect ratio
	const ImageIOParameter *aspect = in.spec().find_attribute ("pixelaspectratio", TypeDesc::FLOAT);
	float pixel_ratio = aspect ? *(float *)aspect->data() : 1.0f;
    float ratio = ((float)in.spec().height+(float)in.spec().y)/((float)in.spec().width+(float)in.spec().x);
	pixel_ratio = pixel_ratio != 0.f ? pixel_ratio : 1.f;
	const int resize_w = 480; // resize target width
    int resize_y = (int)((float)resize_w*ratio/pixel_ratio);
    int resize_x = resize_w;
    
    ImageSpec outspec = outtmp.spec();
	outspec.x = 0;
	outspec.y = 0;
	outspec.full_x = 0;
	outspec.full_y = 0;
    outspec.width = resize_x;
    outspec.height = resize_y;
    outspec.full_width = resize_x;
    outspec.full_height = resize_y;
    ImageBuf out (outputname, outspec);
    float pixel[3] = { .1f, .1f, .1f };
    ImageBufAlgo::fill (out, pixel);
    if(!ImageBufAlgo::resize (out, outtmp, out.xbegin(), out.xend(),
                          out.ybegin(), out.yend()))
    {
        std::cerr << "mkthumbnail: unable to resize image, " << out.geterror() << std::endl;
        return EXIT_FAILURE;
    }

    if(out.spec().nchannels>3) 
    {
        std::cout << "Changing number of channels to 3 "<< "\n";
        ImageBuf newout("temp", out.spec());
        setNbChannels (newout, out, 3);
        out = newout;
    }
    
    if(!out.save (outputname)) 
    {
        std::cerr << "mkthumbnail: unable to save output image, " << out.geterror() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
Beispiel #5
0
static bool
write_mipmap (ImageBufAlgo::MakeTextureMode mode,
              ImageBuf &img, const ImageSpec &outspec_template,
              std::string outputfilename, ImageOutput *out,
              TypeDesc outputdatatype, bool mipmap,
              Filter2D *filter, const ImageSpec &configspec,
              std::ostream &outstream,
              double &stat_writetime, double &stat_miptime)
{
    bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl);

    ImageSpec outspec = outspec_template;
    outspec.set_format (outputdatatype);

    if (mipmap && !out->supports ("multiimage") && !out->supports ("mipmap")) {
        outstream << "maketx ERROR: \"" << outputfilename
                  << "\" format does not support multires images\n";
        return false;
    }

    if (! mipmap && ! strcmp (out->format_name(), "openexr")) {
        // Send hint to OpenEXR driver that we won't specify a MIPmap
        outspec.attribute ("openexr:levelmode", 0 /* ONE_LEVEL */);
    }

    if (mipmap && ! strcmp (out->format_name(), "openexr")) {
        outspec.attribute ("openexr:roundingmode", 0 /* ROUND_DOWN */);
    }

    // OpenEXR always uses border sampling for environment maps
    bool src_samples_border;
    if (envlatlmode && !strcmp(out->format_name(), "openexr")) {
        src_samples_border = true;
        outspec.attribute ("oiio:updirection", "y");
        outspec.attribute ("oiio:sampleborder", 1);
    }
    if (envlatlmode && src_samples_border)
        fix_latl_edges (img);

    Timer writetimer;
    if (! out->open (outputfilename.c_str(), outspec)) {
        outstream << "maketx ERROR: Could not open \"" << outputfilename
                  << "\" : " << out->geterror() << "\n";
        return false;
    }

    // Write out the image
    bool verbose = configspec.get_int_attribute ("maketx:verbose");
    if (verbose) {
        outstream << "  Writing file: " << outputfilename << std::endl;
        outstream << "  Filter \"" << filter->name() << "\" width = " 
                  << filter->width() << "\n";
        outstream << "  Top level is " << formatres(outspec) << std::endl;
    }

    if (! img.write (out)) {
        // ImageBuf::write transfers any errors from the ImageOutput to
        // the ImageBuf.
        outstream << "maketx ERROR: Write failed \" : " << img.geterror() << "\n";
        out->close ();
        return false;
    }

    stat_writetime += writetimer();

    if (mipmap) {  // Mipmap levels:
        if (verbose)
            outstream << "  Mipmapping...\n" << std::flush;
        std::vector<std::string> mipimages;
        std::string mipimages_unsplit = configspec.get_string_attribute ("maketx:mipimages");
        if (mipimages_unsplit.length())
            Strutil::split (mipimages_unsplit, mipimages, ";");
        ImageBuf tmp;
        ImageBuf *big = &img, *small = &tmp;
        while (outspec.width > 1 || outspec.height > 1) {
            Timer miptimer;
            ImageSpec smallspec;

            if (mipimages.size()) {
                // Special case -- the user specified a custom MIP level
                small->reset (mipimages[0]);
                small->read (0, 0, true, TypeDesc::FLOAT);
                smallspec = small->spec();
                if (smallspec.nchannels != outspec.nchannels) {
                    outstream << "WARNING: Custom mip level \"" << mipimages[0]
                              << " had the wrong number of channels.\n";
                    ImageBuf *t = new ImageBuf (mipimages[0], smallspec);
                    ImageBufAlgo::setNumChannels(*t, *small, outspec.nchannels);
                    std::swap (t, small);
                    delete t;
                }
                smallspec.tile_width = outspec.tile_width;
                smallspec.tile_height = outspec.tile_height;
                smallspec.tile_depth = outspec.tile_depth;
                mipimages.erase (mipimages.begin());
            } else {
                // Resize a factor of two smaller
                smallspec = outspec;
                smallspec.width = big->spec().width;
                smallspec.height = big->spec().height;
                smallspec.depth = big->spec().depth;
                if (smallspec.width > 1)
                    smallspec.width /= 2;
                if (smallspec.height > 1)
                    smallspec.height /= 2;
                smallspec.full_width = smallspec.width;
                smallspec.full_height = smallspec.height;
                smallspec.full_depth = smallspec.depth;
                smallspec.set_format (TypeDesc::FLOAT);

                // Trick: to get the resize working properly, we reset
                // both display and pixel windows to match, and have 0
                // offset, AND doctor the big image to have its display
                // and pixel windows match.  Don't worry, the texture
                // engine doesn't care what the upper MIP levels have
                // for the window sizes, it uses level 0 to determine
                // the relatinship between texture 0-1 space (display
                // window) and the pixels.
                smallspec.x = 0;
                smallspec.y = 0;
                smallspec.full_x = 0;
                smallspec.full_y = 0;
                small->alloc (smallspec);  // Realocate with new size
                big->set_full (big->xbegin(), big->xend(), big->ybegin(),
                               big->yend(), big->zbegin(), big->zend());

                if (filter->name() == "box" && filter->width() == 1.0f)
                    ImageBufAlgo::parallel_image (boost::bind(resize_block, small, big, _1, envlatlmode),
                                                  OIIO::get_roi(small->spec()));
                else
                    ImageBufAlgo::parallel_image (boost::bind(resize_block_HQ, small, big, _1, filter),
                                                  OIIO::get_roi(small->spec()));
            }

            stat_miptime += miptimer();
            outspec = smallspec;
            outspec.set_format (outputdatatype);
            if (envlatlmode && src_samples_border)
                fix_latl_edges (*small);

            Timer writetimer;
            // If the format explicitly supports MIP-maps, use that,
            // otherwise try to simulate MIP-mapping with multi-image.
            ImageOutput::OpenMode mode = out->supports ("mipmap") ?
                ImageOutput::AppendMIPLevel : ImageOutput::AppendSubimage;
            if (! out->open (outputfilename.c_str(), outspec, mode)) {
                outstream << "maketx ERROR: Could not append \"" << outputfilename
                          << "\" : " << out->geterror() << "\n";
                return false;
            }
            if (! small->write (out)) {
                // ImageBuf::write transfers any errors from the
                // ImageOutput to the ImageBuf.
                outstream << "maketx ERROR writing \"" << outputfilename
                          << "\" : " << small->geterror() << "\n";
                out->close ();
                return false;
            }
            stat_writetime += writetimer();
            if (verbose) {
                outstream << "    " << formatres(smallspec) << std::endl;
            }
            std::swap (big, small);
        }
    }

    if (verbose)
        outstream << "  Wrote file: " << outputfilename << std::endl;
    writetimer.reset ();
    writetimer.start ();
    if (! out->close ()) {
        outstream << "maketx ERROR writing \"" << outputfilename
                  << "\" : " << out->geterror() << "\n";
        return false;
    }
    stat_writetime += writetimer ();
    return true;
}
Beispiel #6
0
bool
ImageBuf::copy_pixels (const ImageBuf &src)
{
    // compute overlap
    int xbegin = std::max (this->xbegin(), src.xbegin());
    int xend = std::min (this->xend(), src.xend());
    int ybegin = std::max (this->ybegin(), src.ybegin());
    int yend = std::min (this->yend(), src.yend());
    int zbegin = std::max (this->zbegin(), src.zbegin());
    int zend = std::min (this->zend(), src.zend());
    int nchannels = std::min (this->nchannels(), src.nchannels());

    // If we aren't copying over all our pixels, zero out the pixels
    if (xbegin != this->xbegin() || xend != this->xend() ||
        ybegin != this->ybegin() || yend != this->yend() ||
        zbegin != this->zbegin() || zend != this->zend() ||
        nchannels != this->nchannels())
        ImageBufAlgo::zero (*this);

    // Call template copy_pixels_ based on src data type
    switch (src.spec().format.basetype) {
    case TypeDesc::FLOAT :
        copy_pixels_<float> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT8 :
        copy_pixels_<unsigned char> (*this, src, xbegin, xend, ybegin, yend,
                                     zbegin, zend, nchannels);
        break;
    case TypeDesc::INT8  :
        copy_pixels_<char> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT16:
        copy_pixels_<unsigned short> (*this, src, xbegin, xend, ybegin, yend,
                                      zbegin, zend, nchannels);
        break;
    case TypeDesc::INT16 :
        copy_pixels_<short> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT  :
        copy_pixels_<unsigned int> (*this, src, xbegin, xend, ybegin, yend,
                                    zbegin, zend, nchannels);
        break;
    case TypeDesc::INT   :
        copy_pixels_<int> (*this, src, xbegin, xend, ybegin, yend,
                           zbegin, zend, nchannels);
        break;
    case TypeDesc::HALF  :
        copy_pixels_<half> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::DOUBLE:
        copy_pixels_<double> (*this, src, xbegin, xend, ybegin, yend,
                              zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT64:
        copy_pixels_<unsigned long long> (*this, src, xbegin, xend, ybegin, yend,
                                          zbegin, zend, nchannels);
        break;
    case TypeDesc::INT64 :
        copy_pixels_<long long> (*this, src, xbegin, xend, ybegin, yend,
                                 zbegin, zend, nchannels);
        break;
    default:
        ASSERT (0);
    }
    return true;
}