Computes the minimum for each pixel across all bands in the {@link Planar} image.

@param input     Planar image
@param output    Gray scale image containing minimum pixel values
3694
public static void minimum(Planar<GrayF64> input, GrayF64 output) {
		output.reshape(input.width,input.height);
		if (BoofConcurrency.USE_CONCURRENT) {
			ImplImageBandMath_MT.minimum(input, output, 0, input.getNumBands() - 1);
		} else {
			ImplImageBandMath.minimum(input, output, 0, input.getNumBands() - 1);
		}
	}
1295533
@Override
    public ImageSource apply(ImageSource input) {
        int w = input.getWidth();
        int h = input.getHeight();

        MatrixSource output = new MatrixSource(w, h);

        Vector3 s = new Vector3(1, 0, 0);
        Vector3 t = new Vector3(0, 1, 0);

        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {

                if (x < border || x == w - border || y < border || y == h - border) {
                    output.setRGB(x, y, VectorHelper.Z_NORMAL);
                    continue;
                }

                float dh = input.getR(x + 1, y) - input.getR(x - 1, y);
                float dv = input.getR(x, y + 1) - input.getR(x, y - 1);

                s.set(scale, 0, dh);
                t.set(0, scale, dv);

                Vector3 cross = s.crs(t).nor();
                int rgb = VectorHelper.vectorToColor(cross);
                output.setRGB(x, y, rgb);
            }
        }

        return new MatrixSource(output);
    }
1362647
public static void boundImage( GrayS8 img , int min , int max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
825813
public static void boundImage( GrayF64 img , double min , double max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
95462
public static <T extends ImageGray<T>> void maximum(Planar<T> input, T output) {
		maximum(input, output, 0, input.getNumBands() - 1);
	}
658932
@Override
	public void setBand(int x, int y, int band, int value) {
		if (!isInBounds(x, y))
			throw new ImageAccessException("Requested pixel is out of bounds.");
		if (band < 0 || band >= numBands)
			throw new ImageAccessException("Invalid band requested.");

		data[getIndex(x, y, band)] = value;
	}
596760
void constructLinearSystem(Planar<I> input , Se3_F32 g ) {
		int numBands = imageType.getNumBands();

		// first precompute everything that does not depend on pixel values
		inboundsPixels = 0;
		for (int i = 0; i < keypixels.size(); i++) {
			Pixel p = keypixels.data[i];

			// Apply the known warp
			SePointOps_F32.transform(g, p.p3, S);

			if( S.z <= 0 ) {
				p.valid = false;
				continue;
			}

			// Compute projected warped pixel coordinate on image I_1
			p.proj.x = (S.x / S.z) * fx + cx;
			p.proj.y = (S.y / S.z) * fy + cy;

			// make sure it's in the bounds
			if (p.proj.x < 0 || p.proj.x > input.width - 1 || p.proj.y < 0 || p.proj.y > input.height - 1) {
				p.valid = false;
				continue;
			} else {
				p.valid = true;
			}
			inboundsPixels++;

			// pi matrix derivative relative to t at S
			float ZZ = S.z * S.z;

			p.dP11 = fx / S.z;
			p.dP13 = -S.x * fx / ZZ;
			p.dP22 = fy / S.z;
			p.dP23 = -S.y * fy / ZZ;
		}

		// how compute the components which require
		errorOptical = 0;
		int row = 0;
		for (int band = 0; band < numBands; band++) {
			interpDX.setImage(derivX.getBand(band));
			interpDY.setImage(derivY.getBand(band));
			interpI.setImage(input.getBand(band));

			for (int i = 0; i < keypixels.size(); i++) {
				Pixel p = keypixels.data[i];

				if( !p.valid )
					continue;

				// Apply the known warp
				// TODO precompute?
				SePointOps_F32.transform(g, p.p3, S);

				// sample pixel values at warped location in I_1
				// NOTE: This could be highly optimized.  Compute and save interpolation weights once per input
				//       instead of for each band and image (current,dx,dy)
				// TODO create a special bilinear class for this?
				float current = interpI.get( p.proj.x, p.proj.y);
				float dx      = interpDX.get(p.proj.x, p.proj.y);
				float dy      = interpDY.get(p.proj.x, p.proj.y);

				// B = grad^T * dPI/dt = shape(1,3)
				float b1 = dx*p.dP11;
				float b2 = dy*p.dP22;
				float b3 = dx*p.dP13 + dy*p.dP23;

				// C * A(S'(x)) = shape(1,6)
				int indexA = row * 6;
				A.data[indexA++] = -b2*S.z + b3*S.y;
				A.data[indexA++] =  b1*S.z - b3*S.x;
				A.data[indexA++] = -b1*S.y + b2*S.x;
				A.data[indexA++] = b1;
				A.data[indexA++] = b2;
				A.data[indexA]   = b3;

				float error = -(current - p.bands[band]);
				y.data[row] = error;

				errorOptical += Math.abs(error);
				row += 1;
			}
		}
		errorOptical /= row;

		A.numRows = row;
		y.numRows = row;
	}
23420
public static void RGB_to_PLU8(Picture input, Planar<GrayU8> output) {
		if( input.getColor() != ColorSpace.RGB )
			throw new RuntimeException("Unexpected input color space!");
		if( output.getNumBands() != 3 )
			throw new RuntimeException("Unexpected number of bands in output image!");

		output.reshape(input.getWidth(),input.getHeight());

		int dataIn[] = input.getData()[0];

		GrayU8 out0 = output.getBand(0);
		GrayU8 out1 = output.getBand(1);
		GrayU8 out2 = output.getBand(2);

		int indexIn = 0;
		int indexOut = 0;
		for (int i = 0; i < output.height; i++) {
			for (int j = 0; j < output.width; j++, indexOut++ ) {
				int r = dataIn[indexIn++];
				int g = dataIn[indexIn++];
				int b = dataIn[indexIn++];

				out2.data[indexOut] = (byte)r;
				out1.data[indexOut] = (byte)g;
				out0.data[indexOut] = (byte)b;
			}
		}
	}
372478
public static void process(GrayU8 input, GrayU8 output , int radius, @Nullable IWorkArrays work )
	{
		if( work == null )
			work = new IWorkArrays();
		work.reset(256);
		final IWorkArrays _work = work;

		int w = 2*radius+1;

		// sanity check to make sure the image isn't too small to be processed by this algorithm
		if( input.width < w || input.height < w )
			return;

		// defines what the median is. technically this is an approximation because if even it's the ave
		// of the two elements in the middle. I'm not aware of libraries which actually do this.
		int threshold = (w*w)/2+1;

		//CONCURRENT_BELOW BoofConcurrency.loopBlocks(radius, output.height-radius, w,(y0,y1)->{
		final int y0 = radius, y1 = input.height-radius;
		int[] histogram = _work.pop();
		for( int y = y0; y < y1; y++ ) {
			int seed = input.startIndex + (y-radius)*input.stride;
			Arrays.fill(histogram,0);

			// compute the median value for the first x component and initialize the system
			for( int i = 0; i < w; i++ ) {
				int idx = seed + i*input.stride;
				int end = idx + w;
				while( idx < end ) {
					histogram[(input.data[idx++]&0xFF)]++;
				}
			}

			// Compute the median value
			int count = 0, median = 0;
			while( true ) {
				count += histogram[median];
				if( count >= threshold )
					break;
				median++;
			}
			output.data[ output.startIndex+y*output.stride+radius] = (byte)median;

			// remove the left most pixel from the histogram
			count += removeSide(input.data,input.stride, w, histogram, seed, median);

			for( int x = radius+1; x < input.width-radius; x++ ) {
				seed = input.startIndex + (y - radius) * input.stride + (x - radius);

				// add the right most pixels to the histogram
				count += addSide(input.data, input.stride, w, histogram, seed + w - 1, median);

				// find the median, using the previous solution as a starting point
				if (count >= threshold) {
					while (count >= threshold) {
						count -= histogram[median--];
					}
					median += 1;
					count += histogram[median];
				} else {
					while (count < threshold) {
						median += 1;
						count += histogram[median];
					}
				}
				output.data[output.startIndex + y * output.stride + x] = (byte) median;

				// remove the left most pixels from the histogram
				count += removeSide(input.data, input.stride, w, histogram, seed, median);
			}
		}
		//CONCURRENT_ABOVE }});
	}
864147
public static double[] vectorizeDoubleMatrix( RenderedImage input ) {
        double[] U = new double[input.getWidth() * input.getHeight()];
        RandomIter inputRandomIter = RandomIterFactory.create(input, null);

        int j = 0;
        for( int i = 0; i < input.getHeight() * input.getWidth(); i = i + input.getWidth() ) {
            double tmp[] = new double[input.getWidth()];
            for( int k = 0; k < input.getWidth(); k++ ) {
                tmp[k] = inputRandomIter.getSampleDouble(k, j, 0);
            }

            System.arraycopy(tmp, 0, U, i, input.getWidth());
            j++;
        }

        return U;
    }
193028
public static void diag( DMatrix4x4 input , DMatrix4 out ) {
        out.a1 = input.a11;
        out.a2 = input.a22;
        out.a3 = input.a33;
        out.a4 = input.a44;
    }
432575
public static void insertBand( GrayS32 input, int band , InterleavedS32 output) {

		final int numBands = output.numBands;
		for (int y = 0; y < input.height; y++) {
			int indexIn = input.getStartIndex() + y * input.getStride();
			int indexOut = output.getStartIndex() + y * output.getStride() + band;
			int end = indexOut + output.width*numBands - band;
			for (; indexOut < end; indexOut += numBands , indexIn++ ) {
				output.data[indexOut] = input.data[indexIn];
			}
		}
	}
830941
public static void pixelAccess(  BufferedImage input ) {
		// convert the BufferedImage into a Planar
		Planar<GrayU8> image = ConvertBufferedImage.convertFromPlanar(input,null,true,GrayU8.class);

		int x = 10, y = 10;

		// to access a pixel you first access the gray image for the each band
		for( int i = 0; i < image.getNumBands(); i++ )
			System.out.println("Original "+i+" = "+image.getBand(i).get(x,y));

		// change the value in each band
		for( int i = 0; i < image.getNumBands(); i++ )
			image.getBand(i).set(x, y, 100 + i);

		// to access a pixel you first access the gray image for the each band
		for( int i = 0; i < image.getNumBands(); i++ )
			System.out.println("Result   "+i+" = "+image.getBand(i).get(x,y));
	}

	/**
	 * There is no real perfect way that everyone agrees on for converting color images into gray scale
	 * images.  Two examples of how to convert a Planar image into a gray scale image are shown
	 * in this example.
	 */
	public static void convertToGray( BufferedImage input ) {
		// convert the BufferedImage into a Planar
		Planar<GrayU8> image = ConvertBufferedImage.convertFromPlanar(input,null,true,GrayU8.class);

		GrayU8 gray = new GrayU8( image.width,image.height);

		// creates a gray scale image by averaging intensity value across pixels
		ConvertImage.average(image, gray);
		BufferedImage outputAve = ConvertBufferedImage.convertTo(gray,null);

		// convert to gray scale but weigh each color band based on how human vision works
		ColorRgb.rgbToGray_Weighted(image, gray);
		BufferedImage outputWeighted = ConvertBufferedImage.convertTo(gray,null);

		// create an output image just from the first band
		BufferedImage outputBand0 = ConvertBufferedImage.convertTo(image.getBand(0),null);

		gui.addImage(outputAve,"Gray Averaged");
		gui.addImage(outputWeighted,"Gray Weighted");
		gui.addImage(outputBand0,"Band 0");
	}
	
	public static void main( String args[] ) {
		BufferedImage input = UtilImageIO.loadImage(UtilIO.pathExample("apartment_building_02.jpg"));

		// Uncomment lines below to run each example

		ExamplePlanarImages.independent(input);
		ExamplePlanarImages.pixelAccess(input);
		ExamplePlanarImages.convertToGray(input);

		ShowImages.showWindow(gui,"Color Planar Image Examples",true);
	}
}
382860
private BufferedImage scaleBuffered( BufferedImage input ) {
		int m = Math.max(input.getWidth(),input.getHeight());
		if( m <= controls.maxImageSize )
			return input;
		else {
			double scale = controls.maxImageSize/(double)m;
			int w = (int)(scale*input.getWidth()+0.5);
			int h = (int)(scale*input.getHeight()+0.5);

			// Use BoofCV to down sample since Graphics2D introduced too many aliasing artifacts
			BufferedImage output = new BufferedImage(w,h,input.getType());
			Planar<GrayU8> a = new Planar<>(GrayU8.class,input.getWidth(),input.getHeight(),3);
			Planar<GrayU8> b = new Planar<>(GrayU8.class,w,h,3);
			ConvertBufferedImage.convertFrom(input,a,true);
			AverageDownSampleOps.down(a,b);
			ConvertBufferedImage.convertTo(b,output,true);
			return output;
		}
	}
1353997
public static <T extends ImageGray<T>> void average(Planar<T> input, T output) {
		average(input, output, 0, input.getNumBands() - 1);
	}
1059336
public static <T extends ImageBase<T>> void log(T input , T output ) {
		if( input instanceof ImageGray ) {
			if (GrayF32.class == input.getClass()) {
				PixelMath.log((GrayF32) input, (GrayF32) output);
			} else if (GrayF64.class == input.getClass()) {
				PixelMath.log((GrayF64) input, (GrayF64) output);
			} else {
				throw new IllegalArgumentException("Unknown image Type: " + input.getClass().getSimpleName());
			}
		} else if( input instanceof Planar ) {
			Planar in = (Planar)input;
			Planar out = (Planar)output;

			for (int i = 0; i < in.getNumBands(); i++) {
				log( in.getBand(i), out.getBand(i));
			}
		}
	}
995929
public static void boundImage( GrayU16 img , int min , int max ) {
		ImplPixelMath.boundImage(img,min,max);
	}