public override void Trigger(EditableView.ClickPosition.Sources source, EditableView pnlView, Transaction transaction) { IShapeContainer container = CurrentPage.SelectionContainer(); if (container == null) { MessageBox.Show(Strings.Item("Container_Mismatch")); return; } transaction.Edit((Datum)container); Lined mask = FindSourceShape(); ImportedImage image = FindSourceImage(); transaction.Edit(mask); transaction.Edit(image); (mask as Pencil).ForceClosure(transaction); if (mask is Curve curve && !curve.Closed()) { throw new UserException("[Mask_Not_Closed]"); } MaskedImage result = new MaskedImage(image, mask); transaction.Create(result); int index = Math.Max(mask.Z, image.Z); // this will be the Z-order of the new group result.Parent = container; container.Contents.Insert(index + 1, result); // This index will be valid as the individual shapes are still in the list container.Contents.Remove(mask); container.Contents.Remove(image); container.FinishedModifyingContents(transaction, null); CurrentPage.SelectOnly(result); }
/// <summary> /// Creates processed marker file /// </summary> private void CreateProcessedMask(string folder, MaskedImage maskedImage) { try { StringBuilder csvContent = new StringBuilder(); string newFilePath = CreateNewPath(folder, maskedImage.csvMask); // Getting processed mask char[,] processedMask = FileProcess.GetProcessedMask(maskedImage, Effects); // Writing to new File int width = processedMask.GetLength(0); int height = processedMask.GetLength(1); for (int y = 0; y < height; y++) { string line = ""; for (int x = 0; x < width; x++) { line += processedMask[x, y] + ";"; } csvContent.AppendLine(line); } File.AppendAllText(newFilePath, csvContent.ToString()); } catch (Exception e) { System.Windows.Forms.MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
//----------------------------------------------------- public Inpaint(image input, bool[,] mask, int radius) { // initial image this.initial = new MaskedImage(input, mask); // patch radius this.radius = radius; int i = 0; // working copies source = new MaskedImage(initial.width, initial.height); source = initial; target = new MaskedImage(source.width, source.height); Debug.Log("build pyramid of images..."); // build pyramid of downscaled images pyramid = new MaskedImage[12]; this.pyramid[i] = source; //Debug.Log("pyramid0:"+ pyramid[0].width+"/"+pyramid[0].height); while(source.width>radius && source.height>radius) { source = source.downsample(); i++; this.pyramid[i] = new MaskedImage(source.width, source.height); this.pyramid[i] = source; } maxlevel = i+1; }
public static char[,] GetProcessedMask(MaskedImage maskedImage, List <int> effects) { BitmapImage bm = new BitmapImage(new Uri(maskedImage.source)); int indent = EditPageVM.IndentToCrop; char[,] mask = ReadMaskFromCSV(maskedImage.csvMask, bm.PixelWidth, bm.PixelHeight); if (!effects.Contains(EditPageVM.EFFECT_CROP) && !effects.Contains(EditPageVM.EFFECT_ROTATE)) { return(mask); } // Cropping mask if (effects.Contains(EditPageVM.EFFECT_CROP)) { int width = bm.PixelWidth - 2 * indent; int height = bm.PixelHeight - 2 * indent; mask = CropMask(width, height, indent, mask); } // Rotating mask int rotationCount = effects.FindAll(element => element.Equals(EditPageVM.EFFECT_ROTATE)).Count; for (int i = 0; i < rotationCount; i++) { mask = RotateMask90(mask); } return(mask); }
/// <summary> /// Matches images and .csv masks by compairing the names /// </summary> private static bool TryToParceMaskedImages() { List <MaskedImage> parcedImages = new List <MaskedImage>(); int imageCount = PathesToImages.Count(); int maskCount = PathesToCsvFiles.Count(); for (int imgIndx = 0; imgIndx < imageCount; imgIndx++) { string imageName = Path.GetFileNameWithoutExtension(PathesToImages[imgIndx]); for (int maskIndx = 0; maskIndx < maskCount; maskIndx++) { string maskName = Path.GetFileNameWithoutExtension(PathesToCsvFiles[maskIndx]); if (imageName == maskName) { MaskedImage image = new MaskedImage(); image.source = PathesToImages[imgIndx]; image.csvMask = PathesToCsvFiles[maskIndx]; parcedImages.Add(image); break; } } } if (parcedImages.Count > 0) { MaskedImages = parcedImages; return(true); } return(false); }
private void DerivePitchEdges(Image <Bgr, Byte> image) { ThresholdedImage = ImageProcess.ThresholdHsv(image, 22, 89, 33, 240, 40, 250); MaskedImage = image.Copy(ThresholdedImage); CannyImage = MaskedImage.Canny(200, 100); var lines = CannyImage.HoughLinesBinary(1, Math.PI / 360, 100, 200, 50)[0]; foreach (var line in lines) { float dirY = line.Direction.Y; if (line.Length > 500 && dirY < 0.3 && dirY > -0.3f) { if (line.P1.Y < image.Height / 2 && line.P2.Y < image.Height / 2) { m_TopBorderCandidateLines.Enqueue(line); if (m_TopBorderCandidateLines.Count > 20) { m_TopBorderCandidateLines.Dequeue(); } } else if (line.P1.Y > image.Height / 2 && line.P2.Y > image.Height / 2) { m_BottomBorderCandidates.Enqueue(line); if (m_BottomBorderCandidates.Count > 20) { m_BottomBorderCandidates.Dequeue(); } } } } }
//----------------------------------------------------- // distance between two patches in two images public static int distance(MaskedImage source,int xs,int ys, MaskedImage target,int xt,int yt, int S) { long distance=0, wsum=0, ssdmax = 9*255*255; // for each pixel in the source patch for(int dy=-S;dy<=S;dy++) { for(int dx=-S;dx<=S;dx++) { wsum+=ssdmax; int xks=xs+dx, yks=ys+dy; if (xks<1 || xks>=source.width-1) {distance+=ssdmax; continue;} if (yks<1 || yks>=source.height-1) {distance+=ssdmax; continue;} // cannot use masked pixels as a valid source of information if (source.isMasked(xks, yks)) {distance+=ssdmax; continue;} // corresponding pixel in the target patch int xkt=xt+dx, ykt=yt+dy; //Debug.Log("target.width:"+(target.getWidth())); //Debug.Log("xkt:"+xkt+" ykt:"+ykt); if (xkt < 1 || xkt >= target.width-1) { distance += ssdmax; continue; } if (ykt<1 || ykt>=target.height-1) {distance += ssdmax; continue;} // cannot use masked pixels as a valid source of information if (target.isMasked(xkt, ykt)) {distance+=ssdmax; continue;} // SSD distance between pixels (each value is in [0,255^2]) long ssd=0; for(int band=0; band<3; band++) { // pixel values int s_value = source.getSample(xks, yks, band); int t_value = source.getSample(xkt, ykt, band); // pixel horizontal gradients (Gx) float s_gx = 128+(source.getSample(xks+1, yks, band) - source.getSample(xks-1, yks, band))/2; float t_gx = 128+(target.getSample(xkt+1, ykt, band) - target.getSample(xkt-1, ykt, band))/2; // pixel vertical gradients (Gy) float s_gy = 128+(source.getSample(xks, yks+1, band) - source.getSample(xks, yks-1, band))/2; float t_gy = 128+(target.getSample(xkt, ykt+1, band) - target.getSample(xkt, ykt-1, band))/2; ssd += (long) Mathf.Pow(s_value-t_value , 2); // distance between values in [0,255^2] ssd += (long) Mathf.Pow(s_gx-t_gx , 2); // distance between Gx in [0,255^2] ssd += (long) Mathf.Pow(s_gy-t_gy , 2); // distance between Gy in [0,255^2] } // add pixel distance to global patch distance distance += ssd; } } return (int)(DSCALE*distance/wsum); }
//----------------------------------------------------- public MaskedImage(MaskedImage copy) { this.im = copy.im; width = copy.width; height = copy.height; this.mask = new bool[width,height]; for(int y=0;y<height;y++) for(int x=0;x<width;x++) mask[x,y] = copy.mask[x,y]; }
public static Mat ImageToMat_Mask(MaskedImage image) { Mat mat = new Emgu.CV.Mat( image.RowCount, image.ColumnCount, Emgu.CV.CvEnum.DepthType.Cv8U, 1); for(int r = 0; r < image.RowCount; ++r) { for(int c = 0; c < image.ColumnCount; ++c) { byte m = image.HaveValueAt(r, c) ? (byte)255 : (byte)0; mat.SetByteValue(r, c, m); } } return mat; }
public override void Trigger(EditableView.ClickPosition.Sources source, EditableView pnlView, Transaction transaction) { MaskedImage masked = (MaskedImage)CurrentPage.SelectedShapes.First(); IShapeContainer container = (IShapeContainer)masked.Parent; transaction.Edit((Datum)container); transaction.Edit(masked.MaskShape); transaction.Edit(masked.Image); transaction.Delete(masked); masked.Image.Parent = container; masked.MaskShape.Parent = container; container.Contents.Insert(masked.Z + 1, masked.Image); // This index will be valid as the individual shapes are still in the list container.Contents.Insert(masked.Z + 2, masked.MaskShape); container.Contents.Remove(masked); container.FinishedModifyingContents(transaction, null); CurrentPage.SelectOnly(masked.MaskShape); // arbitrarily seemd better to leave the shape selected }
public MatchedImagesTab() { InitializeComponent(); _camImageFirst.ImageSourceChanged += (s, e) => { _imgLeft = new MaskedImage(); _imgLeft.FromBitmapSource(e.NewImage); }; _camImageSec.ImageSourceChanged += (s, e) => { _imgRight = new MaskedImage(); _imgRight.FromBitmapSource(e.NewImage); }; _featureDetector = new FeatureDetectionAlgorithmController(); _featureDetector.StatusChanged += _featureDetector_StatusChanged; }
public FeatureImagesTab() { InitializeComponent(); _camImageFirst.ImageSourceChanged += (s, e) => { ImageLeft = new MaskedImage(); ImageLeft.FromBitmapSource(e.NewImage); }; _camImageSec.ImageSourceChanged += (s, e) => { ImageRight = new MaskedImage(); ImageRight.FromBitmapSource(e.NewImage); }; _matcher = new FeatureMatchingAlgorithm(); _matcher.StatusChanged += _matcher_StatusChanged; _camImageFirst.SelectedPointChanged += OnSelectedPointChanged; _camImageSec.SelectedPointChanged += OnSelectedPointChanged; }
// initialize field from an existing (possibily smaller) NNF public void initialize(NNF nnf) { // field this.field = new int[input.width,input.height,3]; this.input = nnf.input; this.output = nnf.output; this.S = nnf.S; int fx = input.width/nnf.input.width; int fy = input.height/nnf.input.height; //System.out.println("nnf upscale by "+fx+"x"+fy+" : "+nnf.input.W+","+nnf.input.H+" -> "+input.W+","+input.H); for(int y=0;y<input.height;y++) { for(int x=0;x<input.width;x++) { int xlow = Mathf.Min(x/fx, nnf.input.width-1); int ylow = Mathf.Min(y/fy, nnf.input.height-1); field[x,y,0] = nnf.field[xlow,ylow,0]*fx; field[x,y,1] = nnf.field[xlow,ylow,1]*fy; field[x,y,2] = MaskedImage.DSCALE; } } initialize(); }
//----------------------------------------------------- private void weightedCopy(MaskedImage src, int xs, int ys, double[,,] vote, int xd,int yd, double w) { //Debug.Log("src:"+src.width+"/"+src.height+" xs/ys:"+xs+"/"+ys+" xd/yd:"+xd+"/"+yd+ " w: "+w); if (src.isMasked(xs, ys)) return; //Debug.Log("vote: "+vote.GetLength(0)+"/"+vote.GetLength(1)); if(xd<vote.GetLength(0) && yd<vote.GetLength(1)){ vote[xd,yd,0] += w*src.getSample(xs, ys, 0); vote[xd,yd,1] += w*src.getSample(xs, ys, 1); vote[xd,yd,2] += w*src.getSample(xs, ys, 2); vote[xd,yd,3] += w; } else Debug.Log("en dehors"); }
//----------------------------------------------------- // EM-Like algorithm (see "PatchMatch" - page 6) // Returns a double sized target image public MaskedImage ExpectationMaximization(int level) { int iterEM = 1+level/2; int iterNNF = Mathf.Min(7,1+level/2); // source = nnf_SourceToTarget.input; // target = nnf_SourceToTarget.output; newtarget = null; // Debug.Log("source: "+source.width+"/"+source.height); // Debug.Log("target: "+target.width+"/"+target.height); Debug.Log("EM loop (em="+iterEM+",nnf="+iterNNF+") : "); // EM Loop for(int emloop=1;emloop<=iterEM;emloop++) { Debug.Log((1+iterEM-emloop)+" "); // set the new target as current target if (newtarget!=null) { //nnf_SourceToTarget.output = newtarget; nnf_TargetToSource.input = newtarget; target = newtarget; newtarget = null; } // -- add constraint to the NNF if(level>0) { for(int y=0;y<target.height;y++) for(int x=0;x<target.width;x++) if(!source.constainsMasked(x, y, radius)) { nnf_TargetToSource.field[x,y,0] = x; nnf_TargetToSource.field[x,y,1] = y; nnf_TargetToSource.field[x,y,2] = 0; } // -- minimize the NNF nnf_TargetToSource.minimize(iterNNF); } // -- Now we rebuild the target using best patches from source bool upscaled = false; // Instead of upsizing the final target, we build the last target from the next level source image // So the final target is less blurry (see "Space-Time Video Completion" - page 5) if (level>=1 && (emloop==iterEM)) { newsource = pyramid[level-1]; newtarget = target.upscale(newsource.width,newsource.height); //Debug.Log("newsource: "+newsource.width+"/"+newsource.height); upscaled = true; } else { newsource = pyramid[level]; newtarget = target; upscaled = false; } // --- EXPECTATION STEP --- if(level>0) { // votes for best patch from NNF Source->Target (completeness) and Target->Source (coherence) double[,,] vote = new double[newtarget.width,newtarget.width,4]; //ExpectationStep(nnf_SourceToTarget, true, vote, newsource, upscaled); ExpectationStep(nnf_TargetToSource, false, vote, newsource, upscaled); // --- MAXIMIZATION STEP --- // compile votes and update pixel values MaximizationStep(newtarget, vote); } // debug : display intermediary result result = MaskedImage.resize(newtarget.getBufferedImage(), initial.width, initial.height); //Demo.display(result); } return newtarget; }
// constructor public NNF(MaskedImage input, MaskedImage output, int patchsize) { this.input = input; this.output= output; this.S = patchsize; }
//----------------------------------------------------- // Maximization Step : Maximum likelihood of target pixel public void MaximizationStep(MaskedImage target, double[,,] vote) { for(int y=0;y<target.height;y++) { for(int x=0;x<target.width;x++) { if (vote[x,y,3]>0) { int r = (int) ( vote[x,y,0]/vote[x,y,3] ); int g = (int) ( vote[x,y,1]/vote[x,y,3] ); int b = (int) ( vote[x,y,2]/vote[x,y,3] ); target.setSample(x, y, 0, r ); target.setSample(x, y, 1, g ); target.setSample(x, y, 2, b ); target.setMask(x,y,false); } else { // conserve the values from previous target //target.setMask(x,y,true); } } } }
//----------------------------------------------------- // return a downsampled image (factor 1/2) public MaskedImage downsample() { int newW=width/2, newH=height/2; // Binomial coefficient int[] kernel = {1,5,10,10,5,1}; MaskedImage newimage = new MaskedImage(newW, newH); for(int y=0;y<height-1;y+=2) { for(int x=0;x<width-1;x+=2) { int r=0,g=0,b=0,m=0,ksum=0; for(int dy=-2;dy<=3;dy++) { int yk=y+dy; if (yk<0 || yk>=height) continue; int ky = kernel[2+dy]; for(int dx=-2;dx<=3;dx++) { int xk = x+dx; if (xk<0 || xk>=width) continue; if (mask[xk,yk]) continue; int k = kernel[2+dx]*ky; r+= k*this.getSample(xk, yk, 0); g+= k*this.getSample(xk, yk, 1); b+= k*this.getSample(xk, yk, 2); ksum+=k; m++; } } if (ksum>0) {r/=ksum; g/=ksum; b/=ksum;} if (m!=0) { newimage.setSample(x/2, y/2, 0, r); newimage.setSample(x/2, y/2, 1, g); newimage.setSample(x/2, y/2, 2, b); newimage.setMask(x/2, y/2, false); } else { newimage.setMask(x/2, y/2, true); } } } return newimage; }
//----------------------------------------------------- // return an upscaled image public MaskedImage upscale(int newW,int newH) { MaskedImage newimage = new MaskedImage(newW, newH); for(int y=0;y<newH;y++) { for(int x=0;x<newW;x++) { // original pixel int xs = (x*width)/newW; int ys = (y*height)/newH; // copy to new image if (!mask[xs,ys]) { newimage.setSample(x, y, 0, this.getSample(xs, ys, 0)); newimage.setSample(x, y, 1, this.getSample(xs, ys, 1)); newimage.setSample(x, y, 2, this.getSample(xs, ys, 2)); newimage.setMask(x, y, false); } else { newimage.setMask(x, y, true); } } } return newimage; }
// Finds automatically calibration points on standard calibration image // (that is big black dots on white background ) // In point managment one still have to set correct grid number for each point private void FindCalibrationPoints(object sender, RoutedEventArgs e) { if(_imageControl.ImageSource == null) return; _finderChooseWindow.ShowDialog(); if(_finderChooseWindow.Accepted) { _currentImagePointFinder = (CalibrationPointsFinder) _finderChooseWindow.GetSelectedProcessor("Calibration Points Finder"); _currentImagePointFinder.PrimaryShapeChecker = (ShapeChecker) _finderChooseWindow.GetSelectedProcessor("Primary CalibShape Qualifier"); MaskedImage img = new MaskedImage(); img.FromBitmapSource(_imageControl.ImageSource); _currentImagePointFinder.Image = img; _currentImagePointFinder.FindCalibrationPoints(); if(_currentImagePointFinder.Points != null) { _currentImagePointFinder.LinesExtractor.ExtractLines(); _currentImageGrid = _currentImagePointFinder.Points; RefreshCalibrationPoints(); _butAcceptGrid.IsEnabled = true; } } }
public MaskedImage TransfromImageBackwards(IImage image, bool preserveSize = false) { MaskedImage undistorted; FindTransformedImageSize(image.RowCount, image.ColumnCount); Matrix<double>[] matrices = new Matrix<double>[image.ChannelsCount]; if(preserveSize) { undistorted = new MaskedImage(image.Clone()); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(image.RowCount, image.ColumnCount); undistorted.SetMatrix(matrices[i], i); } } else { IImage img = image.Clone(); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(_finalSize.Y, _finalSize.X); img.SetMatrix(matrices[i], i); } undistorted = new MaskedImage(image.Clone()); } int R = InterpolationRadius; int R21 = R * 2 + 1; for(int x = 0; x < matrices[0].ColumnCount; ++x) { for(int y = 0; y < matrices[0].RowCount; ++y) { // Cast point from new image to old one Vector2 oldCoords = Transformation.TransformPointBackwards(new Vector2(x: x, y: y)); Vector2 aa = Transformation.TransformPointForwards(oldCoords); IntVector2 oldPixel = new IntVector2(oldCoords); // Check if point is in old image range or points to undefined point if(oldCoords.X < 0 || oldCoords.X > image.ColumnCount || oldCoords.Y < 0 || oldCoords.Y > image.RowCount || image.HaveValueAt(oldPixel.Y, oldPixel.X) == false) { // Point out of range, so set to black for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i].At(y, x, 0.0); undistorted.SetMaskAt(y, x, false); } } else { // Interpolate value from patch in old image double[,] influence = new double[R21, R21]; double totalInf = 0; // For each pixel in neighbourhood find its distance and influence of Pu on it for(int dx = -R; dx <= R; ++dx) { for(int dy = -R; dy <= R; ++dy) { double distance = _computeDistance(oldCoords, oldPixel.X + dx, oldPixel.Y + dy); influence[dx + R, dy + R] = 1.0 / distance; totalInf += influence[dx + R, dy + R]; } } double infScale = 1.0 / totalInf; // Scale influence, so that its sum over all pixels in radius is 1 double[] val = new double[image.ChannelsCount]; for(int dx = -R; dx <= R; ++dx) { for(int dy = -R; dy <= R; ++dy) { double inf = influence[dx + R, dy + R] * infScale; // Store color for new point considering influence from neighbours int ix = Math.Max(0, Math.Min(image.ColumnCount - 1, oldPixel.X + dx)); int iy = Math.Max(0, Math.Min(image.RowCount - 1, oldPixel.Y + dy)); for(int i = 0; i < image.ChannelsCount; ++i) { val[i] += image[iy, ix, i] * inf; } } } for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i].At(y, x, val[i]); } } } } return undistorted; }
public MaskedImage TransfromImageForwards(IImage image, bool preserveSize = false) { MaskedImage undistorted; var influences = FindInfluenceMatrix(image.RowCount, image.ColumnCount); Matrix<double>[] matrices = new Matrix<double>[image.ChannelsCount]; if(preserveSize) { // New image is in old one's coords undistorted = new MaskedImage(image.Clone()); for(int i = 0; i < image.ChannelsCount; ++i) { matrices[i] = new DenseMatrix(image.RowCount, image.ColumnCount); undistorted.SetMatrix(matrices[i], i); } // Bound processing to smaller of images in each dimesions int minX = Math.Max(0, _finalTopLeft.X); int maxX = Math.Min(image.ColumnCount, _finalSize.X + _finalTopLeft.X); int minY = Math.Max(0, _finalTopLeft.Y); int maxY = Math.Min(image.RowCount, _finalSize.Y + _finalTopLeft.Y); for(int x = minX; x < maxX; ++x) { for(int y = minY; y < maxY; ++y) { double influenceTotal = 0.0; double[] val = new double[image.ChannelsCount]; foreach(var inf in influences[y - _finalTopLeft.Y, x - _finalTopLeft.X]) // Move Pu to influence matrix coords { for(int i = 0; i < image.ChannelsCount; ++i) val[i] += image[inf.Yd, inf.Xd, i] * inf.Influence; influenceTotal += inf.Influence; } if(influenceTotal > 0.25) { for(int i = 0; i < image.ChannelsCount; ++i) matrices[i].At(y, x, val[i] / influenceTotal); undistorted.SetMaskAt(y, x, true); } else { undistorted.SetMaskAt(y, x, false); } } } } else { // New image is in same coords as influence matrix for(int i = 0; i < image.ChannelsCount; ++i) matrices[i] = new DenseMatrix(_finalSize.Y, _finalSize.X); IImage img = image.Clone(); for(int i = 0; i < image.ChannelsCount; ++i) img.SetMatrix(matrices[i], i); undistorted = new MaskedImage(image.Clone()); for(int x = 0; x < _finalSize.X; ++x) { for(int y = 0; y < _finalSize.Y; ++y) { double influenceTotal = 0.0; double[] val = new double[image.ChannelsCount]; foreach(var inf in influences[y, x]) { for(int i = 0; i < image.ChannelsCount; ++i) val[i] += image[inf.Yd, inf.Xd, i] * inf.Influence; influenceTotal += inf.Influence; } if(influenceTotal > 0.5) { for(int i = 0; i < image.ChannelsCount; ++i) matrices[i].At(y, x, val[i] / influenceTotal); undistorted.SetMaskAt(y, x, true); } else { undistorted.SetMaskAt(y, x, false); } } } } return undistorted; }
//----------------------------------------------------- // Expectation Step : vote for best estimations of each pixel public void ExpectationStep(NNF nnf, bool sourceToTarget, double[,,] vote, MaskedImage source, bool upscale) { int[,,] field = nnf.getField(); int R = nnf.S; for(int y=0;y<nnf.input.height;y++) { for(int x=0;x<nnf.input.width;x++) { // x,y = center pixel of patch in input // xp,yp = center pixel of best corresponding patch in output int xp=field[x,y,0], yp=field[x,y,1], dp=field[x,y,2]; // similarity measure between the two patches double w=0; if(dp<MaskedImage.DSCALE+1) w = MaskedImage.similarity[dp]; // vote for each pixel inside the input patch for(int dy=-R;dy<=R;dy++) { for(int dx=-R;dx<=R;dx++) { // get corresponding pixel in output patch int xs,ys,xt,yt; if (sourceToTarget) { xs=x+dx; ys=y+dy; xt=xp+dx; yt=yp+dy; } else { xs=xp+dx; ys=yp+dy; xt=x+dx; yt=y+dy; } if (xs<0 || xs>=nnf.input.width) continue; if (ys<0 || ys>=nnf.input.height) continue; if (xt<0 || xt>=nnf.output.width) continue; if (yt<0 || yt>=nnf.output.height) continue; // add vote for the value if (upscale) { weightedCopy(source, 2*xs, 2*ys, vote, 2*xt, 2*yt, w); weightedCopy(source, 2*xs+1, 2*ys, vote, 2*xt+1, 2*yt, w); weightedCopy(source, 2*xs, 2*ys+1, vote, 2*xt, 2*yt+1, w); weightedCopy(source, 2*xs+1, 2*ys+1, vote, 2*xt+1, 2*yt+1, w); } else weightedCopy(source, xs, ys, vote, xt, yt, w); } } // vote } } }