package gdsc.colocalisation.cda; import java.util.Arrays; /*----------------------------------------------------------------------------- * GDSC Plugins for ImageJ * * Copyright (C) 2011 Alex Herbert * Genome Damage and Stability Centre * University of Sussex, UK * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *---------------------------------------------------------------------------*/ import ij.process.ImageProcessor; public class TwinImageShifter { private ImageProcessor imageIP; private ImageProcessor image2IP; private ImageProcessor roiIP; private ImageProcessor resultIP; private ImageProcessor result2IP; private int xShift = 0; private int yShift = 0; private int w; private int h; private int[][] horizontalROI; private int[][] verticalROI; // Used as working space private int[] t1 = null, t2 = null, t3 = null, t4 = null; public TwinImageShifter(ImageProcessor imageIP, ImageProcessor image2IP, ImageProcessor roiIP) { this.imageIP = imageIP; this.image2IP = image2IP; this.roiIP = roiIP; setup(); } private void setup() { this.w = this.imageIP.getWidth(); this.h = this.imageIP.getHeight(); if (image2IP.getWidth() != w || image2IP.getHeight() != h) { throw new RuntimeException("The first and second channel image dimensions do not match"); } if (roiIP != null) { if (roiIP.getWidth() != w || roiIP.getHeight() != h) { throw new RuntimeException("The channel image and confined image dimensions do not match"); } } buildHorizontalROIArrays(); buildVerticalROIArrays(); createTempArrays(); } private void buildHorizontalROIArrays() { this.horizontalROI = new int[h][]; int[] sites = new int[w]; if (roiIP != null) { for (int y = 0; y < h; ++y) { int size = 0; for (int x = 0, index = y * roiIP.getWidth(); x < w; x++, index++) { if (roiIP.get(index) != 0) { sites[size++] = x; } } // This is the array for height position 'y' horizontalROI[y] = Arrays.copyOf(sites, size); } } else { for (int x = 0; x < w; x++) { sites[x] = x; } for (int y = 0; y < h; ++y) { // This is the array for height position 'y' horizontalROI[y] = sites; } } } private void buildVerticalROIArrays() { this.verticalROI = new int[w][]; int[] sites = new int[h]; if (roiIP != null) { for (int x = 0; x < w; ++x) { int size = 0; for (int y = 0; y < h; ++y) { if (roiIP.get(x, y) != 0) { sites[size++] = y; } } // This is the array for width position 'x' verticalROI[x] = Arrays.copyOf(sites, size); } } else { for (int y = 0; y < h; ++y) { sites[y] = y; } for (int x = 0; x < w; ++x) { // This is the array for width position 'x' verticalROI[x] = sites; } } } private void createTempArrays() { int max = 0; for (int[] list : horizontalROI) if (max < list.length) max = list.length; for (int[] list : verticalROI) if (max < list.length) max = list.length; t1 = new int[max]; t2 = new int[max]; t3 = new int[max]; t4 = new int[max]; } public void run() { // Duplicate the image to ensure the same return type. // This will ensure get and put pixel sets the correct value. this.resultIP = imageIP.duplicate(); this.result2IP = image2IP.duplicate(); // shift and wrap the pixel values in the X-direction // (stores the result in the resultImage) shiftX(); // Shift and wrap the pixel values in the Y-direction. // (stores the result in the resultImage) shiftY(); } private void shiftX() { for (int y = 0; y < h; ++y) { // Find all the locations in this strip that need to be shifted int[] sites = horizontalROI[y]; if (sites.length == 0) { continue; } // Extract the values int index = y * resultIP.getWidth(); for (int i = 0; i < sites.length; i++) { t1[i] = resultIP.get(index + sites[i]); t2[i] = result2IP.get(index + sites[i]); } // Perform a shift rotateArrays(t1, t2, t3, t4, xShift, sites.length); // Write back the values for (int i = 0; i < sites.length; i++) { resultIP.set(index + sites[i], t3[i]); result2IP.set(index + sites[i], t4[i]); } } } private void shiftY() { for (int x = 0; x < w; ++x) { // Find all the locations in this strip that need to be shifted int[] sites = verticalROI[x]; if (sites.length == 0) { continue; } // Extract the values for (int i = 0; i < sites.length; i++) { int index = sites[i] * resultIP.getWidth() + x; t1[i] = resultIP.get(index); t2[i] = result2IP.get(index); } // Perform a shift rotateArrays(t1, t2, t3, t4, yShift, sites.length); // Write back the values for (int i = 0; i < sites.length; i++) { int index = sites[i] * resultIP.getWidth() + x; resultIP.set(index, t3[i]); result2IP.set(index, t4[i]); } } } public void setShiftX(int x) { this.xShift = x; } public void setShiftY(int y) { this.yShift = y; } public void setShift(int x, int y) { this.xShift = x; this.yShift = y; } public ImageProcessor getResultImage() { return this.resultIP; } public ImageProcessor getResultImage2() { return this.result2IP; } private void rotateArrays(int[] array1, int[] array2, int[] array3, int[] array4, int shift, int size) { while (shift < 0) { shift += size; } for (int i = 0; i < size; ++i) { array3[(i + shift) % size] = array1[i]; array4[(i + shift) % size] = array2[i]; } } }