Hy Guys,
I am having problems when I want to play a movie using processing because when I grab a frame to apply a filter of a convolution mask I lose the sound. Everything works fine, but I can´t understand while I can hear only second of the sound and then the rest is off.
Here is my code:
import processing.video.*;
//DECLARATION OF OBJECT MOVIE
Movie myMovie;
//DECLARATION OF IMAGE SOURCE AND IMAGE FILTERED
PImage imgOriginal, imgFilterContornos;
// CONVOLUTION MASK TO DETECT EDGES
float[][] matrixContorno = {
{ -1, -1, -1 },
{ -1, 8, -1 },
{ -1, -1, -1 } };
// DIMENSION OF CONVOLUTION MASK
int matrixsizeContorno = 3;
// OFFSET
int offsetContorno = 128;
final int RED=0, GREEN=1, BLUE=2;
void setup() {
//LOAD THE VIDEO
myMovie = new Movie(this, "cartell_cine.mov");
myMovie.noLoop();
size(1280, 720);
myMovie.play();
frameRate(30);
}
void draw() {
}
// Called every time a new frame is available to read
void movieEvent(Movie m) {
m.read();
//GET THE FRAME
imgOriginal=m;
// I CREATE A NEW IMAGE WITH SAME DIMENSIONS AS ORIGINAL
imgFilterContornos = createImage(imgOriginal.width, imgOriginal.height, RGB);
// LOADING PIXELES TO ALLOW ACCESS TO ARRAY pixels[]
imgOriginal.loadPixels();
imgFilterContornos.loadPixels();
for (int x = 0; x < m.width; x++) {
for (int y = 0; y < m.height; y++) {
// CALCULATING CONVOLUTION
int r = convolution(x, y, matrixContorno, matrixsizeContorno, offsetContorno, imgOriginal,RED);
int g = convolution(x, y, matrixContorno, matrixsizeContorno, offsetContorno, imgOriginal,GREEN);
int b = convolution(x, y, matrixContorno, matrixsizeContorno, offsetContorno, imgOriginal,BLUE);
// I GET THE NEW PIXEL
int loc = x + y * imgOriginal.width;
imgFilterContornos.pixels[loc] = color(r,g,b);
}
}
imgFilterContornos.updatePixels();
set(0,0,imgFilterContornos);
}
// METHOD TO CALCULATE DE SPACIAL CONVOLUTION
int convolution(int x, int y, float[][] matrix, int matrixsize, int offset, PImage img, int canal) {
float result = 0.0;
int half = matrixsize / 2;
// Recorremos la matriz de convolución
for (int i = 0; i < matrixsize; i++) {
for (int j = 0; j < matrixsize; j++) {
// Cálculo del píxel sobre el que estamos trabajando
int xloc = x + i - half;
int yloc = y + j - half;
int loc = xloc + img.width * yloc;
// We make sure that we take a pixel within the valid range. In this case we are
// applying replication of nearby pixel values to pixel locations
// coming out of the image
loc = constrain(loc, 0, img.pixels.length-1);
// Calculation of the convolution operation
// Check the value of the corresponding channel
if (canal==RED)
result += ((imgOriginal.pixels[loc] >> 16 & 0xFF) * matrix[i][j]);
else if (canal==GREEN)
result += ((imgOriginal.pixels[loc] >> 8 & 0xFF) * matrix[i][j]);
else if (canal==BLUE)
result += ((imgOriginal.pixels[loc] & 0xFF) * matrix[i][j]);
}
}
// OFFSET
result += offset;
result = constrain(result, 0, 255);
return (int)result;
}
Thank you in advance!
Related
I was beginning with coding in Processing when I encountered an error which I can't find a solution for.
**DISCLAIMER: I'm new to coding, so I'm having trouble understanding how it works lol
I was attempting to use processing to write a code for a kinect program that would create a ripple effect, but I can't figure out how to define two variables.
Code:
// A simple ripple effect. Click on the image to produce a ripple
// Author: radio79
// Code adapted from http://www.neilwallis.com/java/water.html
// Code adapted from https://forum.processing.org/two/discussion/25348/can-i-apply-ripple-effect-to-kinect
import org.openkinect.processing.*;
Kinect kinect;
PImage img;
Ripple ripple;
void setup() {
size(1920, 1080);
kinect = new Kinect(this);
kinect.initVideo();
img = new PImage(kinect.colorWidth, kinect.colorHeight);
ripple = new Ripple();
//frameRate(60);
}
void draw() {
image(kinect.getVideoImage(), 0, 0);
img.loadPixels();
for (int loc = 0; loc < Kinect.colorWidth * Kinect.colorHeight; loc++) {
img.pixels[loc] = ripple.col[loc];
}
img.updatePixels();
ripple.newframe();
}
class Ripple {
int i, a, b;
int oldind, newind, mapind;
short ripplemap[]; // the height map
int col[]; // the actual pixels
int riprad;
int rwidth, rheight;
int ttexture[];
int ssize;
Ripple() {
// constructor
riprad = 3;
rwidth = width >> 1;
rheight = height >> 1;
ssize = width * (height + 2) * 2;
ripplemap = new short[ssize];
col = new int[width * height];
ttexture = new int[width * height];
oldind = width;
newind = width * (height + 3);
}
void newframe() {
// update the height map and the image
i = oldind;
oldind = newind;
newind = i;
i = 0;
mapind = oldind;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
short data = (short)((ripplemap[mapind - width] + ripplemap[mapind + width] +
ripplemap[mapind - 1] + ripplemap[mapind + 1]) >> 1);
data -= ripplemap[newind + i];
data -= data >> 5;
if (x == 0 || y == 0) // avoid the wraparound effect
ripplemap[newind + i] = 0;
else
ripplemap[newind + i] = data;
// where data = 0 then still, where data > 0 then wave
data = (short)(1024 - data);
// offsets
a = ((x - rwidth) * data / 1024) + rwidth;
b = ((y - rheight) * data / 1024) + rheight;
//bounds check
if (a >= width)
a = width - 1;
if (a < 0)
a = 0;
if (b >= height)
b = height-1;
if (b < 0)
b=0;
col[i] = img.pixels[a + (b * width)];
mapind++;
i++;
}
}
}
}
void mouseDragged() {
for (int j = mouseY - ripple.riprad; j < mouseY + ripple.riprad; j++) {
for (int k = mouseX - ripple.riprad; k < mouseX + ripple.riprad; k++) {
if (j >= 0 && j < height && k>= 0 && k < width) {
ripple.ripplemap[ripple.oldind + (j * width) + k] += 512;
}
}
}
}
The error is: 'The global variable "x" does not exist', 'The global variable "y" does not exist' and so forth. Please help.
The variables I need help defining appear on line 18 for the first time, they are colorWidth and colorHeight
The line reads:
img = new PImage(kinect.colorWidth, kinect.colorHeight);
The colorWidth and colorHeight are underlined in red.
I have tried using this method:
public
float colorWidth;
float colorHeight;
But, only the second line appears to be defined properly. The first line emits the message "colorWidth cannot be resolved or is not a field" when the program runs, or "illegal modifier for parameter colorWidth; only final is permitted" when the underline is clicked.
Picture of what the program shows after the public code
PLEASE HELP!!! Thank you!
The keyword public here just means nothing, it must be said of a function or variable. And you just don't need it. So removing it should fix the problem!
I have created a sample SWT application. I am uploading few images into the application. I have to resize all the images which are above 16x16 (Width*Height) resolution and save those in separate location.
For this reason I am scaling the image and saving the scaled image to my destination location. Below is the piece of code which I am using to do that.
Using getImageData() to get the image data and to save I am using ImageLoader save() method.
final Image mySampleImage = ImageResizer.scaleImage(img, 16, 16);
final ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] { mySampleImage.getImageData() };
final String fileExtension = inputImagePath.substring(inputImagePath.lastIndexOf(".") + 1);
if ("GIF".equalsIgnoreCase(fileExtension)) {
imageLoader.save(outputImagePath, SWT.IMAGE_GIF);
} else if ("PNG".equalsIgnoreCase(fileExtension)) {
imageLoader.save(outputImagePath, SWT.IMAGE_PNG);
}
ImageLoader imageLoader.save(outputImagePath, SWT.IMAGE_GIF); is throwing the below exeception when I am trying to save few specific images (GIF or PNG format).
org.eclipse.swt.SWTException: Unsupported color depth
at org.eclipse.swt.SWT.error(SWT.java:4533)
at org.eclipse.swt.SWT.error(SWT.java:4448)
at org.eclipse.swt.SWT.error(SWT.java:4419)
at org.eclipse.swt.internal.image.GIFFileFormat.unloadIntoByteStream(GIFFileFormat.java:427)
at org.eclipse.swt.internal.image.FileFormat.unloadIntoStream(FileFormat.java:124)
at org.eclipse.swt.internal.image.FileFormat.save(FileFormat.java:112)
at org.eclipse.swt.graphics.ImageLoader.save(ImageLoader.java:218)
at org.eclipse.swt.graphics.ImageLoader.save(ImageLoader.java:259)
at mainpackage.ImageResizer.resize(ImageResizer.java:55)
at mainpackage.ImageResizer.main(ImageResizer.java:110)
Let me know If there is any other way to do the same (or) there is any way to resolve this issue.
Finally I got a solution by referring to this existing eclipse bug Unsupported color depth eclipse bug.
In the below code i have created a PaletteData with RGB values and updated my Image Data.
My updateImagedata() method will take the scaled image and will return the proper updated imageData if the image depth is 32 or more.
private static ImageData updateImagedata(Image image) {
ImageData data = image.getImageData();
if (!data.palette.isDirect && data.depth <= 8)
return data;
// compute a histogram of color frequencies
HashMap<RGB, ColorCounter> freq = new HashMap<>();
int width = data.width;
int[] pixels = new int[width];
int[] maskPixels = new int[width];
for (int y = 0, height = data.height; y < height; ++y) {
data.getPixels(0, y, width, pixels, 0);
for (int x = 0; x < width; ++x) {
RGB rgb = data.palette.getRGB(pixels[x]);
ColorCounter counter = (ColorCounter) freq.get(rgb);
if (counter == null) {
counter = new ColorCounter();
counter.rgb = rgb;
freq.put(rgb, counter);
}
counter.count++;
}
}
// sort colors by most frequently used
ColorCounter[] counters = new ColorCounter[freq.size()];
freq.values().toArray(counters);
Arrays.sort(counters);
// pick the most frequently used 256 (or fewer), and make a palette
ImageData mask = null;
if (data.transparentPixel != -1 || data.maskData != null) {
mask = data.getTransparencyMask();
}
int n = Math.min(256, freq.size());
RGB[] rgbs = new RGB[n + (mask != null ? 1 : 0)];
for (int i = 0; i < n; ++i)
rgbs[i] = counters[i].rgb;
if (mask != null) {
rgbs[rgbs.length - 1] = data.transparentPixel != -1 ? data.palette.getRGB(data.transparentPixel)
: new RGB(255, 255, 255);
}
PaletteData palette = new PaletteData(rgbs);
ImageData newData = new ImageData(width, data.height, 8, palette);
if (mask != null)
newData.transparentPixel = rgbs.length - 1;
for (int y = 0, height = data.height; y < height; ++y) {
data.getPixels(0, y, width, pixels, 0);
if (mask != null)
mask.getPixels(0, y, width, maskPixels, 0);
for (int x = 0; x < width; ++x) {
if (mask != null && maskPixels[x] == 0) {
pixels[x] = rgbs.length - 1;
} else {
RGB rgb = data.palette.getRGB(pixels[x]);
pixels[x] = closest(rgbs, n, rgb);
}
}
newData.setPixels(0, y, width, pixels, 0);
}
return newData;
}
To find minimum index:
static int closest(RGB[] rgbs, int n, RGB rgb) {
int minDist = 256*256*3;
int minIndex = 0;
for (int i = 0; i < n; ++i) {
RGB rgb2 = rgbs[i];
int da = rgb2.red - rgb.red;
int dg = rgb2.green - rgb.green;
int db = rgb2.blue - rgb.blue;
int dist = da*da + dg*dg + db*db;
if (dist < minDist) {
minDist = dist;
minIndex = i;
}
}
return minIndex;
}
ColourCounter Class:
class ColorCounter implements Comparable<ColorCounter> {
RGB rgb;
int count;
public int compareTo(ColorCounter o) {
return o.count - count;
}
}
Basically, what I need to do is take a 2d array of bitflags and produce a list of 2d rectangles to fill the entire area with the minimum number of total shapes required to perfectly fill the space. I am doing this to convert a 2d top-down monochrome of a map into 2d rectangle shapes which perfectly represent the passed in image which will be used to generate a platform in a 3d world. I need to minimize the total number of shapes used, because each shape will represent a separate object, and flooding it with 1 unit sized squares for each pixel would be highly inefficient for that engine.
So far I have read in the image, processed it, and filled a two dimensional array of booleans which tells me if the pixel should be filled or unfilled, but I am unsure of the most efficient approach of continuing.
Here is what I have so far, as reference, if you aren't following:
public static void main(String[] args) {
File file = new File(args[0]);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (IOException ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
if (bi != null) {
int[] rgb = bi.getRGB(0, 0, bi.getWidth(), bi.getHeight(), new int[bi.getWidth() * bi.getHeight()], 0, bi.getWidth());
Origin origin = new Origin(bi.getWidth() / 2, bi.getHeight() / 2);
boolean[][] flags = new boolean[bi.getWidth()][bi.getHeight()];
for (int y = 0; y < bi.getHeight(); y++) {
for (int x = 0; x < bi.getWidth(); x++) {
int index = y * bi.getWidth() + x;
int color = rgb[index];
int type = color == Color.WHITE.getRGB() ? 1 : (color == Color.RED.getRGB() ? 2 : 0);
if (type == 2) {
origin = new Origin(x, y);
}
flags[x][y] = type != 1;
}
}
List<Rectangle> list = new ArrayList();
//Fill list with rectangles
}
}
White represents no land. Black or Red represents land. The check for the red pixel marks the origin position of map, which was just for convenience and the rectangles will be offset by the origin position if it is found.
Edit: The processing script does not need to be fast, the produced list of rectangles will be dumped and that will be what will be imported and used later, so the processing of the image does not need to be particularly optimized, it doesn't make a difference.
I also just realized that expecting a 'perfect' solution is expecting too much, since this would qualify as a 'knapsack problem' of the multidimensionally constrained variety, if I am expecting exactly the fewest number of rectangles, so simply an algorithm that produces a minimal number of rectangles will suffice.
Here is a reference image for completion:
Edit 2: It doesn't look like this is such an easy thing to answer given no feedback yet, but I have started making progress, but I am sure I am missing something that would vastly reduce the number of rectangles. Here is the updated progress:
static int mapWidth;
static int mapHeight;
public static void main(String[] args) {
File file = new File(args[0]);
BufferedImage bi = null;
System.out.println("Reading image...");
try {
bi = ImageIO.read(file);
} catch (IOException ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
if (bi != null) {
System.out.println("Complete!");
System.out.println("Interpreting image...");
mapWidth = bi.getWidth();
mapHeight = bi.getHeight();;
int[] rgb = bi.getRGB(0, 0, mapWidth, mapHeight, new int[mapWidth * mapHeight], 0, mapWidth);
Origin origin = new Origin(mapWidth / 2, mapHeight / 2);
boolean[][] flags = new boolean[mapWidth][mapHeight];
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
int index = y * mapWidth + x;
int color = rgb[index];
int type = color == Color.WHITE.getRGB() ? 1 : (color == Color.RED.getRGB() ? 2 : 0);
if (type == 2) {
origin = new Origin(x, y);
}
flags[x][y] = type != 1;
}
}
System.out.println("Complete!");
System.out.println("Processing...");
//Get Rectangles to fill space...
List<Rectangle> rectangles = getRectangles(flags, origin);
System.out.println("Complete!");
float rectangleCount = rectangles.size();
float totalCount = mapHeight * mapWidth;
System.out.println("Total units: " + (int)totalCount);
System.out.println("Total rectangles: " + (int)rectangleCount);
System.out.println("Rectangle reduction factor: " + ((1 - rectangleCount / totalCount) * 100.0) + "%");
System.out.println("Dumping data...");
try {
file = new File(file.getParentFile(), file.getName() + "_Rectangle_Data.txt");
if(file.exists()){
file.delete();
}
file.createNewFile();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
for(Rectangle rect: rectangles){
bw.write(rect.x + "," + rect.y + "," + rect.width + ","+ rect.height + "\n");
}
bw.flush();
bw.close();
} catch (Exception ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
System.out.println("Complete!");
}else{
System.out.println("Error!");
}
}
public static void clearRange(boolean[][] flags, int xOff, int yOff, int width, int height) {
for (int y = yOff; y < yOff + height; y++) {
for (int x = xOff; x < xOff + width; x++) {
flags[x][y] = false;
}
}
}
public static boolean checkIfFilled(boolean[][] flags, int xOff, int yOff, int width, int height) {
for (int y = yOff; y < yOff + height; y++) {
for (int x = xOff; x < xOff + width; x++) {
if (!flags[x][y]) {
return false;
}
}
}
return true;
}
public static List<Rectangle> getRectangles(boolean[][] flags, Origin origin) {
List<Rectangle> rectangles = new ArrayList();
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
if (flags[x][y]) {
int maxWidth = 1;
int maxHeight = 1;
Loop:
//The search size limited to 400x400 so it will complete some time this century.
for (int w = Math.min(400, mapWidth - x); w > 1; w--) {
for (int h = Math.min(400, mapHeight - y); h > 1; h--) {
if (w * h > maxWidth * maxHeight) {
if (checkIfFilled(flags, x, y, w, h)) {
maxWidth = w;
maxHeight = h;
break Loop;
}
}
}
}
//Search also in the opposite direction
Loop:
for (int h = Math.min(400, mapHeight - y); h > 1; h--) {
for (int w = Math.min(400, mapWidth - x); w > 1; w--) {
if (w * h > maxWidth * maxHeight) {
if (checkIfFilled(flags, x, y, w, h)) {
maxWidth = w;
maxHeight = h;
break Loop;
}
}
}
}
rectangles.add(new Rectangle(x - origin.x, y - origin.y, maxWidth, maxHeight));
clearRange(flags, x, y, maxWidth, maxHeight);
}
}
}
return rectangles;
}
My current code's search for larger rectangles is limited to 400x400 to speed up testing, and outputs 17,979 rectangles, which is a 99.9058% total reduction of rectangles if I treated each pixel as a 1x1 square(19,095,720 pixels). So far so good.
I'm creating a method that takes two parameters with 2 indexes a start and an end that takes a location of the picture being edited and turn those pixels to a different color. Using a while loop to index start and end.
The problem I'm having is I'm only a getting a really small portion to change color:
Don't mind some of the code that is commented out. I was trying a bunch of different things.
public void negative(int start, int end)
{
Pixel[] pixelArray = this.getPixels(); //pixelarray index
Pixel pixel = null;
// int height = this.getHeight();
//int paintPoint = height / 2;
//int width = this.getWidth();
int i = 0;
int red, green, blue = 0;
// int x = 0;
Pixel topPixel = null;
Pixel bottomPixel = null;
//int startY;
//int startX;
int y = start;
int x = end;
//int count;
while( y < this.getHeight())
{
y++;
while (x < this.getWidth()) //loops through index
{
pixel = this.getPixel(x,y);
red = pixel.getRed();
green = pixel.getGreen();//collects color green
blue = pixel.getBlue();//collects color blue
Color negColor = new Color( 255 - red, 255 - green, 255 - blue);//sets new values of pixels
pixel.setColor(negColor);
x++;
//count = count + 1;
i++;//indexes continuing
}
}
}
A picture is 2D yet you are treating it as 1D (notice after once through your inner x loop it never is reset to its min value). If you wish to color an arbitrary rectangle within a given photo the parms should include two points : minx, miny and maxx maxy then your pair of 2D loops visits each point in that region line by line.
// do sanity checks on your parms
if (this.getWidth() < maxx) {
maxx = this.getWidth();
}
if (this.getHeight() < maxy) {
maxy = this.getHeight();
}
if (minx < 0) {
minx = 0;
}
if (miny < 0) {
miny = 0;
}
for (y = mixy; y < maxy; y++) {
for (x = mixx; x < maxx; x++) {
// now your have valid x and y values
}
}
I have problems with extracting a pictogram into some further processable format, since now I have got like this:
Part of the current solution is taken from the BoofCV ImageTresholding example. My code for this solution the following:
import georegression.metric.UtilAngle;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.IOException;
import boofcv.alg.color.ColorHsv;
import boofcv.alg.filter.binary.BinaryImageOps;
import boofcv.alg.filter.binary.GThresholdImageOps;
import boofcv.alg.filter.binary.ThresholdImageOps;
import boofcv.gui.ListDisplayPanel;
import boofcv.gui.binary.VisualizeBinaryData;
import boofcv.gui.image.ImagePanel;
import boofcv.gui.image.ShowImages;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.io.image.UtilImageIO;
import boofcv.struct.image.ImageFloat32;
import boofcv.struct.image.ImageUInt8;
import boofcv.struct.image.MultiSpectral;
public class Binaryzation {
static double splitFraction = 0.05;
static double minimumSideFraction = 0.1;
static ListDisplayPanel gui = new ListDisplayPanel();
public static void printClickedColor(final BufferedImage image) {
ImagePanel gui = new ImagePanel(image);
gui.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
float[] color = new float[3];
int rgb = image.getRGB(e.getX(), e.getY());
ColorHsv.rgbToHsv((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF,
rgb & 0xFF, color);
System.out.println("H = " + color[0] + " S = " + color[1]
+ " V = " + color[2]);
try {
showSelectedColor("Selected", image, color[0], color[1]);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
ShowImages.showWindow(gui, "Color Selector");
}
public static void showSelectedColor(String name, BufferedImage image,
float hue, float saturation) throws IOException {
ImageUInt8 binary = binaryTreshold(name, image, hue, saturation);
// MAGIC HAPPENDS -removing small objects
ImageUInt8 filtered = BinaryImageOps.erode4(binary, 1, null);
filtered = BinaryImageOps.dilate8(filtered, 1, null);
filtered = BinaryImageOps.removePointNoise(filtered, filtered);
ShowImages.showWindow(filtered, "Binary " + name);
BufferedImage visualFiltered1 = VisualizeBinaryData.renderBinary(
filtered, true, null);
ShowImages.showWindow(visualFiltered1, "Mask");
BufferedImage visualFiltered12 = Fill.fill(visualFiltered1);
ShowImages.showWindow(visualFiltered12, "Filled Mask");
ImageUInt8 mask = ConvertBufferedImage.convertFromSingle(
visualFiltered12, null, ImageUInt8.class);
ImageUInt8 wynik = new ImageUInt8(mask.width, mask.height);
//subtraction of images: wynik=mask-filtered;
int min = 0;
int max = 1;
for (int i = 0; i < mask.height; i++) {
// System.out.println("i=" + i);
for (int j = 0; j < mask.width; j++) {
// System.out.println("j=" + j);
if (filtered.get(j, i) < min)
min = filtered.get(j, i);
if (filtered.get(j, i) > max)
max = filtered.get(j, i);
int filtInt = filtered.get(j, i);
if (filtInt >= 1)
filtInt = 1;
else if (filtInt < 1)
filtInt = 0;
int maskInt = mask.get(j, i);
if (maskInt >= 1)
maskInt = 0;
else if (maskInt < 1)
maskInt = 1;
int diff = maskInt - filtInt;
if (diff == 1) {
diff = 255;
wynik.set(j, i, diff);
} else if (diff == 0) {
diff = 0;
wynik.set(j, i, diff);
} else {
diff = 255;
wynik.set(j, i, diff);
}
}
}
ShowImages.showWindow(wynik, "Wynik=Mask-Filtered");
wynik = BinaryImageOps.erode4(wynik, 1, null);
wynik = BinaryImageOps.dilate8(wynik, 1, null);
wynik = BinaryImageOps.removePointNoise(wynik, wynik);
UtilImageIO.saveImage(wynik, "C:/dev/zdjeciaTestowe/wynik.jpg");
ShowImages.showWindow(wynik, "Wynik=Mask-Filtered After noise remove");
}
private static ImageUInt8 binaryTreshold(String name, BufferedImage image,
float hue, float saturation) throws IOException {
MultiSpectral<ImageFloat32> input = ConvertBufferedImage
.convertFromMulti(image, null, true, ImageFloat32.class);
MultiSpectral<ImageFloat32> hsv = input.createSameShape();
// Convert into HSV
ColorHsv.rgbToHsv_F32(input, hsv);
// Euclidean distance squared threshold for deciding which pixels are
// members of the selected set
float maxDist2 = 0.4f * 0.4f;
// Extract hue and saturation bands which are independent of intensity
ImageFloat32 H = hsv.getBand(0);
ImageFloat32 S = hsv.getBand(1);
// Adjust the relative importance of Hue and Saturation.
// Hue has a range of 0 to 2*PI and Saturation from 0 to 1.
float adjustUnits = (float) (Math.PI / 2.0);
// step through each pixel and mark how close it is to the selected
// color
BufferedImage output = new BufferedImage(input.width, input.height,
BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < hsv.height; y++) {
for (int x = 0; x < hsv.width; x++) {
// Hue is an angle in radians, so simple subtraction doesn't
// work
float dh = UtilAngle.dist(H.unsafe_get(x, y), hue);
float ds = (S.unsafe_get(x, y) - saturation) * adjustUnits;
// this distance measure is a bit naive, but good enough for to
// demonstrate the concept
float dist2 = dh * dh + ds * ds;
if (dist2 <= maxDist2) {
System.out.println(image.getRGB(x, y));
output.setRGB(x, y, image.getRGB(x, y));
}
}
}
ImageFloat32 output1 = ConvertBufferedImage.convertFromSingle(output,
null, ImageFloat32.class);
ImageUInt8 binary = new ImageUInt8(input.width, input.height);
double threshold = GThresholdImageOps.computeOtsu(output1, 0, 255);
// Apply the threshold to create a binary image
ThresholdImageOps.threshold(output1, binary, (float) threshold, true);
return binary;
}
public static void main(String args[]) throws IOException {
BufferedImage image = UtilImageIO
.loadImage("C:/dev/zdjeciaTestowe/images.jpg");
// Let the user select a color
printClickedColor(image);
// Display pre-selected colors
showSelectedColor("Yellow", image, 1f, 1f);
}
}
import java.awt.image.BufferedImage;
import boofcv.struct.image.ImageUInt8;
public class Fill {
private static final int BLACK = -16777216;
private static final int WHITE = -1;
/**
* #param input Buffered image
* #return image with filled holes
*/
public static BufferedImage fill(BufferedImage input) {
int width = input.getWidth();
int height = input.getHeight();
BufferedImage output=new BufferedImage(width, height, input.getType());
for (int i = 0; i < height; i++) {
// System.out.println("i=" + i);
for (int j = 0; j < width; j++) {
// System.out.println("j=" + j);
if (input.getRGB(j, i) == WHITE) {
output.setRGB(j, i, WHITE);
} else if (isPreviusWhite(j, i, input)
&& isAnotherWhiteInLine(j, i, input)) {
output.setRGB(j, i, WHITE);
}
}
}
return output;
}
private static boolean isPreviusWhite(int i, int i2, BufferedImage input) {
boolean condition = false;
while (1 < i2) {
if (input.getRGB(i, i2) == WHITE)
return true;
i2--;
}
return condition;
}
private static boolean isAnotherWhiteInLine(int j, int i,
BufferedImage input) {
boolean condition = false;
while (j < input.getWidth()) {
if (input.getRGB(j, i) == WHITE)
return true;
j++;
}
return condition;
}
}
I know how to extract a pictogram on a sign, and i have done it by subtracting the Mask from Filled Mask but have problem to obtain some processable result,
because int the end I have an image in grayscale not a binary image (or as it is in boofCV ImageUInt8).
How do I properly do subtraction of two images in ImageUInt8 format so the result would be also ImageUInt8?
Today i have wrote futher part of that algorithm and now the problem which i want to ask about is more clarified. Here is added code (part from //subtraction of images: wynik=mask-filtered;) and 2 additional pictures as product of processing.
The problem is that last image after noise remove is solid black and without any information. How to correctly convert image to obtain processable content??
What i'm doing wrong?
I have found solution to my problem on the last picture "Wynik=Mask-Filtered After noise Remove" there is a pictogram but diffirence beetwen piksels in grayscale is so low that it's hard to see so problemsolver is adding:
GrayImageOps.stretch(wynik, 125, 125, 255, wynik);