diff options
Diffstat (limited to 'jni/feature_mos/src/mosaic/Blend.cpp')
-rw-r--r-- | jni/feature_mos/src/mosaic/Blend.cpp | 183 |
1 files changed, 173 insertions, 10 deletions
diff --git a/jni/feature_mos/src/mosaic/Blend.cpp b/jni/feature_mos/src/mosaic/Blend.cpp index 6988ace..7308a53 100644 --- a/jni/feature_mos/src/mosaic/Blend.cpp +++ b/jni/feature_mos/src/mosaic/Blend.cpp @@ -41,11 +41,12 @@ Blend::~Blend() if (m_pFrameYPyr) free(m_pFrameYPyr); } -int Blend::initialize(int blendingType, int frame_width, int frame_height) +int Blend::initialize(int blendingType, int stripType, int frame_width, int frame_height) { this->width = frame_width; this->height = frame_height; this->m_wb.blendingType = blendingType; + this->m_wb.stripType = stripType; m_wb.blendRange = m_wb.blendRangeUV = BLEND_RANGE_DEFAULT; m_wb.nlevs = m_wb.blendRange; @@ -95,13 +96,27 @@ void Blend::AlignToMiddleFrame(MosaicFrame **frames, int frames_size) } } -int Blend::runBlend(MosaicFrame **frames, int frames_size, +int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes, + int frames_size, ImageType &imageMosaicYVU, int &mosaicWidth, int &mosaicHeight, float &progress, bool &cancelComputation) { int ret; int numCenters; + MosaicFrame **frames; + + // For THIN strip mode, accept all frames for blending + if (m_wb.stripType == STRIP_TYPE_THIN) + { + frames = oframes; + } + else // For WIDE strip mode, first select the relevant frames to blend. + { + SelectRelevantFrames(oframes, frames_size, rframes, frames_size); + frames = rframes; + } + ComputeBlendParameters(frames, frames_size, true); numCenters = frames_size; @@ -348,6 +363,75 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite, site_idx++; } + ////////// imgMos.Y, imgMos.V, imgMos.U are used as follows ////////////// + ////////////////////// THIN STRIP MODE /////////////////////////////////// + + // imgMos.Y is used to store the index of the image from which each pixel + // in the output mosaic can be read out for the thin-strip mode. Thus, + // there is no special handling for pixels around the seam. Also, imgMos.Y + // is set to 255 wherever we can't get its value from any input image e.g. + // in the gray border areas. imgMos.V and imgMos.U are set to 128 for the + // thin-strip mode. + + ////////////////////// WIDE STRIP MODE /////////////////////////////////// + + // imgMos.Y is used the same way as the thin-strip mode. + // imgMos.V is used to store the index of the neighboring image which + // should contribute to the color of an output pixel in a band around + // the seam. Thus, in this band, we will crossfade between the color values + // from the image index imgMos.Y and image index imgMos.V. imgMos.U is + // used to store the weight (multiplied by 100) that each image will + // contribute to the blending process. Thus, we start at 99% contribution + // from the first image, then go to 50% contribution from each image at + // the seam. Then, the contribution from the second image goes up to 99%. + + // For WIDE mode, set the pixel masks to guide the blender to cross-fade + // between the images on either side of each seam: + if (m_wb.stripType == STRIP_TYPE_WIDE) + { + // Set the number of pixels around the seam to cross-fade between + // the two component images, + int tw = STRIP_CROSS_FADE_WIDTH * width; + + for(int y = 0; y < imgMos.Y.height; y++) + { + for(int x = tw; x < imgMos.Y.width - tw + 1; ) + { + // Determine where the seam is... + if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y][x+1] && + imgMos.Y.ptr[y][x] != 255 && + imgMos.Y.ptr[y][x+1] != 255) + { + // Find the image indices on both sides of the seam + unsigned char idx1 = imgMos.Y.ptr[y][x]; + unsigned char idx2 = imgMos.Y.ptr[y][x+1]; + + for (int o = tw; o >= 0; o--) + { + // Set the image index to use for cross-fading + imgMos.V.ptr[y][x - o] = idx2; + // Set the intensity weights to use for cross-fading + imgMos.U.ptr[y][x - o] = 50 + (99 - 50) * o / tw; + } + + for (int o = 1; o <= tw; o++) + { + // Set the image index to use for cross-fading + imgMos.V.ptr[y][x + o] = idx1; + // Set the intensity weights to use for cross-fading + imgMos.U.ptr[y][x + o] = imgMos.U.ptr[y][x - o]; + } + + x += (tw + 1); + } + else + { + x++; + } + } + } + } + // Now perform the actual blending using the frame assignment determined above site_idx = 0; for(CSite *csite = m_AllSites; csite < esite; csite++) @@ -683,9 +767,36 @@ void Blend::ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRec int inMask = ((unsigned) ii < imgMos.Y.width && (unsigned) jj < imgMos.Y.height) ? 1 : 0; - if(inMask && imgMos.Y.ptr[jj][ii]!=site_idx && imgMos.Y.ptr[jj][ii]!=255) + if(inMask && imgMos.Y.ptr[jj][ii] != site_idx && + imgMos.V.ptr[jj][ii] != site_idx && + imgMos.Y.ptr[jj][ii] != 255) continue; + // Setup weights for cross-fading + // Weight of the intensity already in the output pixel + double wt0 = 0.0; + // Weight of the intensity from the input pixel (current frame) + double wt1 = 1.0; + + if (m_wb.stripType == STRIP_TYPE_WIDE) + { + if(inMask && imgMos.Y.ptr[jj][ii] != 255) + { + if(imgMos.V.ptr[jj][ii] == 128) // Not on a seam + { + wt0 = 0.0; + wt1 = 1.0; + } + else + { + wt0 = 1.0; + wt1 = ((imgMos.Y.ptr[jj][ii] == site_idx) ? + (double)imgMos.U.ptr[jj][ii] / 100.0 : + 1.0 - (double)imgMos.U.ptr[jj][ii] / 100.0); + } + } + } + // Project this mosaic point into the original frame coordinate space double xx, yy; @@ -696,6 +807,8 @@ void Blend::ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRec if(inMask) { imgMos.Y.ptr[jj][ii] = 255; + wt0 = 0.0f; + wt1 = 1.0f; } } @@ -708,15 +821,19 @@ void Blend::ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRec // Final destination in extended pyramid #ifndef LINEAR_INTERP - if(inSegment(x1, sptr->width, BORDER-1) && inSegment(y1, sptr->height, BORDER-1)) + if(inSegment(x1, sptr->width, BORDER-1) && + inSegment(y1, sptr->height, BORDER-1)) { double xfrac = xx - x1; double yfrac = yy - y1; - dptr->ptr[j][i] = (short) (.5 + ciCalc(sptr, x1, y1, xfrac, yfrac)); + dptr->ptr[j][i] = (short) (wt0 * dptr->ptr[j][i] + .5 + + wt1 * ciCalc(sptr, x1, y1, xfrac, yfrac)); if (dvptr >= m_pMosaicVPyr && nC > 0) { - duptr->ptr[j][i] = (short) (.5 + ciCalc(suptr, x1, y1, xfrac, yfrac)); - dvptr->ptr[j][i] = (short) (.5 + ciCalc(svptr, x1, y1, xfrac, yfrac)); + duptr->ptr[j][i] = (short) (wt0 * duptr->ptr[j][i] + .5 + + wt1 * ciCalc(suptr, x1, y1, xfrac, yfrac)); + dvptr->ptr[j][i] = (short) (wt0 * dvptr->ptr[j][i] + .5 + + wt1 * ciCalc(svptr, x1, y1, xfrac, yfrac)); } } #else @@ -755,11 +872,14 @@ void Blend::ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRec clipToSegment(x1, sptr->width, BORDER); clipToSegment(y1, sptr->height, BORDER); - dptr->ptr[j][i] = sptr->ptr[y1][x1]; + dptr->ptr[j][i] = (short) (wt0 * dptr->ptr[j][i] + 0.5 + + wt1 * sptr->ptr[y1][x1] ); if (dvptr >= m_pMosaicVPyr && nC > 0) { - dvptr->ptr[j][i] = svptr->ptr[y1][x1]; - duptr->ptr[j][i] = suptr->ptr[y1][x1]; + dvptr->ptr[j][i] = (short) (wt0 * dvptr->ptr[j][i] + + 0.5 + wt1 * svptr->ptr[y1][x1] ); + duptr->ptr[j][i] = (short) (wt0 * duptr->ptr[j][i] + + 0.5 + wt1 * suptr->ptr[y1][x1] ); } } } @@ -907,7 +1027,50 @@ void Blend::FrameToMosaicRect(int width, int height, double trs[3][3], BlendRect } } +void Blend::SelectRelevantFrames(MosaicFrame **frames, int frames_size, + MosaicFrame **relevant_frames, int &relevant_frames_size) +{ + MosaicFrame *first = frames[0]; + MosaicFrame *last = frames[frames_size-1]; + MosaicFrame *mb; + + double fxpos = first->trs[0][2], fypos = first->trs[1][2]; + + double midX = last->width / 2.0; + double midY = last->height / 2.0; + double z = ProjZ(first->trs, midX, midY, 1.0); + double firstX, firstY; + double prevX = firstX = ProjX(first->trs, midX, midY, z, 1.0); + double prevY = firstY = ProjY(first->trs, midX, midY, z, 1.0); + + relevant_frames[0] = first; // Add first frame by default + relevant_frames_size = 1; + for (int i = 0; i < frames_size - 1; i++) + { + mb = frames[i]; + double currX, currY; + z = ProjZ(mb->trs, midX, midY, 1.0); + currX = ProjX(mb->trs, midX, midY, z, 1.0); + currY = ProjY(mb->trs, midX, midY, z, 1.0); + double deltaX = currX - prevX; + double deltaY = currY - prevY; + double center2centerDist = sqrt(deltaY * deltaY + deltaX * deltaX); + + if (fabs(deltaX) > STRIP_SEPARATION_THRESHOLD * last->width) + { + relevant_frames[relevant_frames_size] = mb; + relevant_frames_size++; + + prevX = currX; + prevY = currY; + } + } + + // Add last frame by default + relevant_frames[relevant_frames_size] = last; + relevant_frames_size++; +} void Blend::ComputeBlendParameters(MosaicFrame **frames, int frames_size, int is360) { |