| 101 | } |
| 102 | |
| 103 | void LensDistortOp::begin( const CompoundObject * operands ) |
| 104 | { |
| 105 | // Get the lens model parameters. |
| 106 | IECore::CompoundObjectPtr lensModelParams( runTimeCast<CompoundObject>( lensParameter()->getValue() ) ); |
| 107 | |
| 108 | // Load the lens object. |
| 109 | m_lensModel = LensModel::create( lensModelParams ); |
| 110 | m_lensModel->validate(); |
| 111 | |
| 112 | // Get the distortion mode. |
| 113 | m_mode = m_modeParameter->getNumericValue(); |
| 114 | |
| 115 | // Get our image information. |
| 116 | assert( runTimeCast< ImagePrimitive >(inputParameter()->getValue()) ); |
| 117 | ImagePrimitive *inputImage = static_cast<ImagePrimitive *>( inputParameter()->getValue() ); |
| 118 | |
| 119 | Imath::Box2i dataWindow( inputImage->getDataWindow() ); |
| 120 | Imath::Box2i displayWindow( inputImage->getDisplayWindow() ); |
| 121 | double displayWH[2] = { static_cast<double>( displayWindow.size().x + 1 ), static_cast<double>( displayWindow.size().y + 1 ) }; |
| 122 | double displayOrigin[2] = { static_cast<double>( displayWindow.min[0] ), static_cast<double>( displayWindow.min[1] ) }; |
| 123 | |
| 124 | // Get the distorted window. |
| 125 | // As the LensModel::bounds() method requires that the display window has it's origin at (0,0) in the bottom left of the image and the ImagePrimitive has it's origin in the top left, |
| 126 | // convert to the correct image space and offset if by the display window's origin if it is non-zero. |
| 127 | Imath::Box2i distortionSpaceBox( |
| 128 | Imath::V2i( dataWindow.min[0] - displayWindow.min[0], displayWindow.size().y - ( dataWindow.max[1] - displayWindow.min[1] ) ), |
| 129 | Imath::V2i( dataWindow.max[0] - displayWindow.min[0], displayWindow.size().y - ( dataWindow.min[1] - displayWindow.min[1] ) ) |
| 130 | ); |
| 131 | |
| 132 | // Calculate the distorted data window. |
| 133 | Imath::Box2i distortedWindow = m_lensModel->bounds( m_mode, distortionSpaceBox, ( displayWindow.size().x + 1 ), ( displayWindow.size().y + 1 ) ); |
| 134 | |
| 135 | // Convert the distorted data window back to the same image space as ImagePrimitive. |
| 136 | m_distortedDataWindow = Imath::Box2i( |
| 137 | Imath::V2i( distortedWindow.min[0] + displayWindow.min[0], ( displayWindow.size().y - distortedWindow.max[1] ) + displayWindow.min[1] ), |
| 138 | Imath::V2i( distortedWindow.max[0] + displayWindow.min[0], ( displayWindow.size().y - distortedWindow.min[1] ) + displayWindow.min[1] ) |
| 139 | ); |
| 140 | |
| 141 | // Compute a 2D cache of the warped points for use in the warp() method. |
| 142 | IECore::FloatVectorDataPtr cachePtr = new IECore::FloatVectorData; |
| 143 | std::vector<float> &cache( cachePtr->writable() ); |
| 144 | cache.resize( ( m_distortedDataWindow.size().x + 1 ) * ( m_distortedDataWindow.size().y + 1 ) * 2 ); // We interleave the X and Y vector components within the cache. |
| 145 | |
| 146 | for( int y = distortedWindow.max.y, pixelIndex = 0; y >= distortedWindow.min.y; --y ) |
| 147 | { |
| 148 | for( int x = distortedWindow.min.x; x <= distortedWindow.max.x; ++x ) |
| 149 | { |
| 150 | // Convert to UV space with the origin in the bottom left. |
| 151 | Imath::V2f p( Imath::V2f( x, y ) ); |
| 152 | Imath::V2d uv( p[0] / displayWH[0], p[1] / displayWH[1] ); |
| 153 | |
| 154 | // Get the distorted uv coordinate. |
| 155 | Imath::V2d duv( m_mode == kDistort ? m_lensModel->distort( uv ) : m_lensModel->undistort( uv ) ); |
| 156 | |
| 157 | // Transform it to image space. |
| 158 | p = Imath::V2f( |
| 159 | duv[0] * displayWH[0] + displayOrigin[0], ( ( displayWH[1] - 1. ) - ( duv[1] * displayWH[1] ) ) + displayOrigin[1] |
| 160 | ); |