I am trying to run the feature detection program of javacv to compare the similar features in 2 images however I am getting a runtimeexception. Since I am completely new to javacv I don't know how to resolve this.
The exception trace is
OpenCV Error: Assertion failed (queryDescriptors.type() == trainDescCollection[0].type()) in unknown function, file ..\..\..\src\opencv\modules\features2d\src\matchers.cpp, line 351
Exception in thread "main" java.lang.RuntimeException: ..\..\..\src\opencv\modules\features2d\src\matchers.cpp:351: error: (-215) queryDescriptors.type() == trainDescCollection[0].type()
at com.googlecode.javacv.cpp.opencv_features2d$DescriptorMatcher.match(Native Method)
at Ex7DescribingSURF.main(Ex7DescribingSURF.java:63)
Here is the source code
import static com.googlecode.javacv.cpp.opencv_core.NORM_L2;
import static com.googlecode.javacv.cpp.opencv_core.cvCreateImage;
import static com.googlecode.javacv.cpp.opencv_features2d.drawMatches;
import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;
import java.util.Arrays;
import java.util.Comparator;
import javax.swing.JFrame;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.CvScalar;
import com.googlecode.javacv.cpp.opencv_core.CvSize;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_features2d.BFMatcher;
import com.googlecode.javacv.cpp.opencv_features2d.DMatch;
import com.googlecode.javacv.cpp.opencv_features2d.DescriptorExtractor;
import com.googlecode.javacv.cpp.opencv_features2d.DrawMatchesFlags;
import com.googlecode.javacv.cpp.opencv_features2d.KeyPoint;
import com.googlecode.javacv.cpp.opencv_nonfree.SURF;
public class Ex7DescribingSURF {
/**
* Example for section "Describing SURF features" in chapter 8, page 212.
*
* Computes SURF features, extracts their descriptors, and finds best
* matching descriptors between two images of the same object. There are a
* couple of tricky steps, in particular sorting the descriptors.
*/
public static void main(String[] args) {
IplImage img = cvLoadImage("A.jpg");
IplImage template = cvLoadImage("B.jpg");
IplImage images[] = { img, template };
// Setup SURF feature detector and descriptor.
double hessianThreshold = 2500d;
int nOctaves = 4;
int nOctaveLayers = 2;
boolean extended = true;
boolean upright = false;
SURF surf = new SURF(hessianThreshold, nOctaves, nOctaveLayers,
extended, upright);
DescriptorExtractor surfDesc = DescriptorExtractor.create("SURF");
KeyPoint keyPoints[] = { new KeyPoint(), new KeyPoint() };
CvMat descriptors[] = new CvMat[2];
// Detect SURF features and compute descriptors for both images
for (int i = 0; i < 1; i++) {
surf.detect(images[i], null, keyPoints[i]);
// Create CvMat initialized with empty pointer, using simply `new
// CvMat()` leads to an exception.
descriptors[i] = new CvMat(null);
surfDesc.compute(images[i], keyPoints[i], descriptors[i]);
}
// Create feature matcher
BFMatcher matcher = new BFMatcher(NORM_L2, true);
DMatch matches = new DMatch();
// "match" is a keyword in Scala, to avoid conflict between a keyword
// and a method match of the BFMatcher,
// we need to enclose method name in ticks: `match`.
matcher.match(descriptors[0], descriptors[1], matches, null);
System.out.println("Matched: " + matches.capacity());
// Select only 25 best matches
DMatch bestMatches = selectBest(matches, 25);
// Draw best matches
IplImage imageMatches = cvCreateImage(new CvSize(images[0].width()
+ images[1].width(), images[0].height()), images[0].depth(), 3);
drawMatches(images[0], keyPoints[0], images[1], keyPoints[1],
bestMatches, imageMatches, CvScalar.BLUE, CvScalar.RED, null,
DrawMatchesFlags.DEFAULT);
CanvasFrame canvas = new CanvasFrame("");
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.showImage(imageMatches);
}
// ----------------------------------------------------------------------------------------------------------------
/** Select only the best matches from the list. Return new list. */
private static DMatch selectBest(DMatch matches, int numberToSelect) {
// Convert to Scala collection for the sake of sorting
int oldPosition = matches.position();
DMatch a[] = new DMatch[matches.capacity()];
for (int i = 0; i < a.length; i++) {
DMatch src = matches.position(i);
DMatch dest = new DMatch();
copy(src, dest);
a[i] = dest;
}
// Reset position explicitly to avoid issues from other uses of this
// position-based container.
matches.position(oldPosition);
// Sort
DMatch aSorted[] = a;
Arrays.sort(aSorted, new DistanceComparator());
// DMatch aSorted[]=sort(a);
// Create new JavaCV list
DMatch best = new DMatch(numberToSelect);
for (int i = 0; i < numberToSelect; i++) {
// Since there is no may to `put` objects into a list DMatch,
// We have to reassign all values individually, and hope that API
// will not any new ones.
copy(aSorted[i], best.position(i));
}
// Set position to 0 explicitly to avoid issues from other uses of this
// position-based container.
best.position(0);
return best;
}
private static void copy(DMatch src, DMatch dest) {
// TODO: use Pointer.copy() after JavaCV/JavaCPP 0.3 is released
// (http://code.google.com/p/javacpp/source/detail?r=51f4daa13d618c6bd6a5556ff2096d0e834638cc)
// dest.put(src)
dest.distance(src.distance());
dest.imgIdx(src.imgIdx());
dest.queryIdx(src.queryIdx());
dest.trainIdx(src.trainIdx());
}
static class DistanceComparator implements Comparator<DMatch> {
public int compare(DMatch o1, DMatch o2) {
if (o1.compare(o2))
return -1;
else
return 1;
}
};
}
Does anybody know what I might need more to make this work.. Any help appreciated
As the error clearly says that descriptor types does not match. You have to check for the condition if the descriptor types match.
A simple if statement before matcher.match would solve your problem
if (descriptors[0].type() == descriptors[1].type())
{
matcher.match(descriptors[0], descriptors[1], matches, null);
System.out.println("Matched: " + matches.capacity());
}
The CvMat was not initialized properly which was giving the error.
descriptors[i] = new CvMat(null);
Instead I put it like this which solved the problem.
descriptors[i] = CvMat.create(1, 1);
Don't know if still needed, but I found answer. In code there's problem with this loop:
for (int i = 0; i < 1; i++) {
surf.detect(images[i], null, keyPoints[i]);
// Create CvMat initialized with empty pointer, using simply `new
// CvMat()` leads to an exception.
descriptors[i] = new CvMat(null);
surfDesc.compute(images[i], keyPoints[i], descriptors[i]);
}
i is just 0, than the loop exits and you try to use object descriptors[1] which is absent.
Change it to for( int i = 0, i < 2, i++) {
Related
I could create seprately the "page x of y" and re-ordered the TOC with the official examples. "Page x of y" is created according to iText 7: Building Blocks Chapter 7: Handling events; setting viewer preferences and writer properties with the examples Solving the "Page X of Y" problem; and TOC is created with reference to iText 7 examples TOC as first page.
Now I want the generated PDF to have both "page x of y" and re-ordered TOC. And "page x of y" shall be shown on all pages, i.e. on the 1st page (the TOC page), it shall show "Page 1 of 35", the 2nd page (start page of the main text) shall show "Page 2 of 35" (In this Jekyll and Hyde example, TOC has one page).
But when I tried to put "page x of y" and re-order TOC together, I found a problem in the generated PDF: the 1st page (the TOC page) showed correctly "Page 1 of 35", but the 2nd page (start page of the main text) showed also "Page 1 of 35".
What is the tricks to let the 2nd page to show "Page 2 of 35" with re-ordered TOC?
==code for Page X of Y and re-order TOC==
package main;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import com.itextpdf.io.IOException;
import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfOutline;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.draw.DottedLine;
import com.itextpdf.kernel.pdf.navigation.PdfDestination;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Tab;
import com.itextpdf.layout.element.TabStop;
import com.itextpdf.layout.hyphenation.HyphenationConfig;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.property.AreaBreakType;
import com.itextpdf.layout.property.TabAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.renderer.ParagraphRenderer;
public class CreateTOC {
public static final String SRC = "D:/work/java_workspace/result/jekyll_hyde.txt";
public static final String DEST = "D:/work/java_workspace/result/test_toc.pdf";
public static void main(String args[]) throws IOException, Exception {
File file = new File(DEST);
file.getParentFile().mkdirs();
new CreateTOC().createPdf(DEST);
}
public void createPdf(String dest) throws IOException, java.io.IOException {
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
pdf.getCatalog().setPageMode(PdfName.UseOutlines);
PageXofY event = new PageXofY(pdf);
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, event);
PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.HELVETICA_BOLD);
Document document = new Document(pdf);
document.setTextAlignment(TextAlignment.JUSTIFIED)
.setHyphenation(new HyphenationConfig("en", "uk", 3, 3))
.setFont(font)
.setFontSize(11);
// // add the cover
// document.add(new Paragraph("this is the cover 1"));
// document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
//
//
// document.add(new Paragraph("this is the cover 2"));
// document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
// parse text to PDF
BufferedReader br = new BufferedReader(new FileReader(SRC));
String name, line;
Paragraph p;
boolean title = true;
int counter = 0;
PdfOutline outline = null;
List<SimpleEntry<String,SimpleEntry<String, Integer>>> toc = new ArrayList<>();
while ((line = br.readLine()) != null) {
p = new Paragraph(line);
p.setKeepTogether(true);
if (title) {
name = String.format("title%02d", counter++);
outline = createOutline(outline, pdf, line, name);
int pagesWithoutCover = pdf.getNumberOfPages();
SimpleEntry<String, Integer> titlePage = new SimpleEntry(line, pagesWithoutCover);
p.setFont(bold).setFontSize(12)
.setKeepWithNext(true)
.setDestination(name)
.setNextRenderer(new UpdatePageRenderer(p, titlePage));
title = false;
document.add(p);
toc.add(new SimpleEntry(name, titlePage));
}
else {
p.setFirstLineIndent(18);
if (line.isEmpty()) {
p.setMarginBottom(12);
title = true;
}
else {
p.setMarginBottom(0);
}
document.add(p);
}
}
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
// create table of contents
int startToc = pdf.getNumberOfPages();
p = new Paragraph().setFont(bold).add("Table of Contents").setDestination("toc");
document.add(p);
toc.remove(0);
List<TabStop> tabstops = new ArrayList();
tabstops.add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
for (SimpleEntry<String, SimpleEntry<String, Integer>> entry : toc) {
SimpleEntry<String, Integer> text = entry.getValue();
p = new Paragraph()
.addTabStops(tabstops)
.add(text.getKey())
// .setFixedLeading(150)
.add(new Tab())
.add(String.valueOf(text.getValue()))
.setAction(PdfAction.createGoTo(entry.getKey()));
document.add(p);
}
int tocPages = pdf.getNumberOfPages() - startToc;
// reorder pages
PdfPage page;
for (int i = 0; i <= tocPages; i++) {
page = pdf.removePage(startToc + i);
pdf.addPage(i + 1, page);
}
event.writeTotal(pdf);
document.close();
}
protected class UpdatePageRenderer extends ParagraphRenderer {
protected SimpleEntry<String, Integer> entry;
public UpdatePageRenderer(Paragraph modelElement, SimpleEntry<String, Integer> entry) {
super(modelElement);
this.entry = entry;
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
entry.setValue(layoutContext.getArea().getPageNumber());
return result;
}
}
public PdfOutline createOutline(PdfOutline outline, PdfDocument pdf, String title, String name) {
if (outline == null) {
outline = pdf.getOutlines(false);
outline = outline.addOutline(title);
outline.addDestination(PdfDestination.makeDestination(new PdfString(name)));
return outline;
}
PdfOutline kid = outline.addOutline(title);
kid.addDestination(PdfDestination.makeDestination(new PdfString(name)));
return outline;
}
protected class PageXofY implements IEventHandler {
protected PdfFormXObject placeholder;
protected float side = 20;
protected float x = 300;
protected float y = 25;
protected float space = 4.5f;
protected float descent = 3;
public PageXofY(PdfDocument pdf) {
placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
}
#Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNumber = pdf.getPageNumber(page);
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.newContentStreamBefore(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
Paragraph p = new Paragraph().add("Page ").add(String.valueOf(pageNumber)).add(" of");
canvas.showTextAligned(p, x, y, TextAlignment.RIGHT);
pdfCanvas.addXObject(placeholder, x + space, y - descent);
pdfCanvas.release();
}
public void writeTotal(PdfDocument pdf) {
Canvas canvas = new Canvas(placeholder, pdf);
canvas.showTextAligned(String.valueOf(pdf.getNumberOfPages()),
0, descent, TextAlignment.LEFT);
}
}
}
In general
You will obviously run into trouble if you first create pages including a "page x/y" using the current page number of each page and then re-order the pages.
If you know beforehand how many pages you will move up front, you can take this re-ordering into account by adding this number as offset to the page number in your event listener. Be sure to reset that offset when you start creating the TOC pages.
If you don't know that number, it does not make sense to try to number the pages before re-ordering at all. Instead add page numbers afterwards as described in the iText 7: Building Blocks Chapter 2: Working with the RootElement example Adding a Page X of Y footer, i.e. loop over every page in the document and add a "Page X of Y" Paragraph to each page:
int n = pdf.getNumberOfPages();
Paragraph footer;
for (int page = 1; page <= n; page++) {
footer = new Paragraph(String.format("Page %s of %s", page, n));
document.showTextAligned(footer, 297.5f, 20, page,
TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0);
}
document.close();
Don't forget to set immediateFlush to false as described right after that example.
Using an offset
In a comment you indicated that you did not want to use the solution from chapter 2 referenced above as you didn't want to keep the whole PDF in memory. Then you posted your code.
Thus, let's try and implement the offset mentioned above in your code.
The offset variable is best located right in the event listener. Having added it, it might looks like this:
protected class PageXofY implements IEventHandler
{
// vvv added
int offset = 0;
// ^^^ added
protected PdfFormXObject placeholder;
protected float side = 20;
protected float x = 300;
protected float y = 25;
protected float space = 4.5f;
protected float descent = 3;
public PageXofY(PdfDocument pdf)
{
placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
}
#Override
public void handleEvent(Event event)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNumber = pdf.getPageNumber(page);
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.newContentStreamBefore(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
// vvv changed
Paragraph p = new Paragraph().add("Page ").add(String.valueOf(pageNumber + offset)).add(" of");
// ^^^ changed
canvas.showTextAligned(p, x, y, TextAlignment.RIGHT);
pdfCanvas.addXObject(placeholder, x + space, y - descent);
pdfCanvas.release();
}
public void writeTotal(PdfDocument pdf)
{
Canvas canvas = new Canvas(placeholder, pdf);
canvas.showTextAligned(String.valueOf(pdf.getNumberOfPages()),
0, descent, TextAlignment.LEFT);
}
}
(PageXofY)
(You might want to add getters and setters for the offset.)
When importing the text body your page numbers currently are created off-by-one as the TOC page will later be pulled up to the front. Thus, you need to use an offset of 1 (1 page TOC) during that import.
Afterwards, before starting the TOC page, you will have to reset the offset to 0 as nothing will be pulled before the TOC page thereafter.
Id est:
public void createPdf(Reader reader, String dest) throws IOException
{
[...]
Document document = new Document(pdf);
document.setTextAlignment(TextAlignment.JUSTIFIED)
.setHyphenation(new HyphenationConfig("en", "uk", 3, 3))
.setFont(font)
.setFontSize(11);
// vvv added
event.offset = 1;
// ^^^ added
// // add the cover
[...]
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
// vvv added
event.offset = 0;
// ^^^ added
// create table of contents
int startToc = pdf.getNumberOfPages();
[...]
}
(CreateTOC method createPdf)
In the current iText 7 development 7.0.3-SNAPSHOT version this results in desired page numbering.
Beware: There had been reports on delayed page event execution. Probably the event timing meanwhile has been changed. With older versions, therefore, the code might still apply wrong page numbers.
My plan is to write a mutation-less code in D-language so that my values are available by runtime. Someone spoke to me about loop-unrolling and compile time code generation but I have no clear idea how to do that. I have made the D-template below but it has no guarantee to be evaluated at compile-time because on the two assignment statements(mutations) . Advice would be greatly appreciated. Suggestions could be preferably in D or C++ without macros.
import std.stdio;
import std.string;
import std.conv;
const char[] ALPHABET="ABFCDFRGHDSTHFG";
const string pattern="ABA";
I[C] computeAtCompileTime(S ,C,I)( const S pattern ){
I[C] table1;
const int size = to!int(pattern.length) ;//Length of the pattern to be matched
foreach( c; ALPHABET){ //Initialise array
table1[c] = size;
}
foreach(i; 0..size-1){
table1[pattern[i]] = size -i-1;
}
return table1;
}
enum TableFromCompiler = computeAtCompileTime!(const string ,char, int)(pattern);
void main(){
// enum TableFromCompiler = computeAtCompileTime!(const string ,char, int)(pattern);
writeln(TableFromCompiler);
}
import std.stdio;
immutable char[] ALPHABET = "ABFCDFRGHDSTHFG";
int[char] compute(in string pattern)
{
int[char] table;
foreach (c; ALPHABET) {
table[c] = cast(int)pattern.length;
}
foreach (i, c; pattern) {
table[c] = cast(int)(pattern.length - i - 1);
}
return table;
}
void main()
{
enum table = compute("ABA");
writeln(table);
}
Output:
['A':0, 'B':1, 'C':3, 'D':3, 'F':3, 'G':3, 'H':3, 'R':3, 'S':3, 'T':3]
Code on dpaste.
Using processing I am trying to run a script that will process a folder full of frames.
The script is a combination of PixelSortFrames and SortThroughSeamCarving.
I am new to processing and what I want does not seems to be working. I would like the script to run back through and choose the following file in the folder to be processed. At the moment it stops at the end and does not return to start on next file (there are three other modules also involved).
Any help would be much appreciated. :(
/* ASDFPixelSort for video frames v1.0
Original ASDFPixelSort by Kim Asendorf <http://kimasendorf.com>
https://github.com/kimasendorf/ASDFPixelSort
Fork by dx <http://dequis.org> and chinatsu <http://360nosco.pe>
// Main configuration
String basedir = ".../Images/Seq_002"; // Specify the directory in which the frames are located. Use forward slashes.
String fileext = ".jpg"; // Change to the format your images are in.
int resumeprocess = 0; // If you wish to resume a previously stopped process, change this value.
boolean reverseIt = true;
boolean saveIt = true;
int mode = 2; // MODE: 0 = black, 1 = bright, 2 = white
int blackValue = -10000000;
int brightnessValue = -1;
int whiteValue = -6000000;
// -------
PImage img, original;
float[][] sums;
int bottomIndex = 0;
String[] filenames;
int row = 0;
int column = 0;
int i = 0;
java.io.File folder = new java.io.File(dataPath(basedir));
java.io.FilenameFilter extfilter = new java.io.FilenameFilter() {
boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(fileext);
}
};
void setup() {
if (resumeprocess > 0) {i = resumeprocess - 1;frameCount = i;}
size(1504, 1000); // Resolution of the frames. It's likely there's a better way of doing this..
filenames = folder.list(extfilter);
size(1504, 1000);
println(" " + width + " x " + height + " px");
println("Creating buffer images...");
PImage hImg = createImage(1504, 1000, RGB);
PImage vImg = createImage(1504, 1000, RGB);
// draw image and convert to grayscale
if (i +1 > filenames.length) {println("Uh.. Done!"); System.exit(0);}
img = loadImage(basedir+"/"+filenames[i]);
original = loadImage(basedir+"/"+filenames[i]);
image(img, 0, 0);
filter(GRAY);
img.loadPixels(); // updatePixels is in the 'runKernals'
// run kernels to create "energy map"
println("Running kernals on image...");
runKernels(hImg, vImg);
image(img, 0, 0);
// sum pathways through the image
println("Getting sums through image...");
sums = getSumsThroughImage();
image(img, 0, 0);
loadPixels();
// get start point (smallest value) - this is used to find the
// best seam (starting at the lowest energy)
bottomIndex = width/2;
// bottomIndex = findStartPoint(sums, 50);
println("Bottom index: " + bottomIndex);
// find the pathway with the lowest information
int[] path = new int[height];
path = findPath(bottomIndex, sums, path);
for (int bi=0; bi<width; bi++) {
// get the pixels of the path from the original image
original.loadPixels();
color[] c = new color[path.length]; // create array of the seam's color values
for (int i=0; i<c.length; i++) {
try {
c[i] = original.pixels[i*width + path[i] + bi]; // set color array to values from original image
}
catch (Exception e) {
// when we run out of pixels, just ignore
}
}
println(" " + bi);
c = sort(c); // sort (use better algorithm later)
if (reverseIt) {
c = reverse(c);
}
for (int i=0; i<c.length; i++) {
try {
original.pixels[i*width + path[i] + bi] = c[i]; // reverse! set the pixels of the original from sorted array
}
catch (Exception e) {
// when we run out of pixels, just ignore
}
}
original.updatePixels();
}
// when done, update pixels to display
updatePixels();
// display the result!
image(original, 0, 0);
if (saveIt) {
println("Saving file...");
//filenames = stripFileExtension(filenames);
save("results/SeamSort_" + filenames + ".tiff");
}
println("DONE!");
}
// strip file extension for saving and renaming
String stripFileExtension(String s) {
s = s.substring(s.lastIndexOf('/')+1, s.length());
s = s.substring(s.lastIndexOf('\\')+1, s.length());
s = s.substring(0, s.lastIndexOf('.'));
return s;
}
This code works by processing all images in the selected folder
String basedir = "D:/things/pixelsortframes"; // Specify the directory in which the frames are located. Use forward slashes.
String fileext = ".png"; // Change to the format your images are in.
int resumeprocess = 0; // If you wish to resume a previously stopped process, change this value.
int mode = 1; // MODE: 0 = black, 1 = bright, 2 = white
int blackValue = -10000000;
int brightnessValue = -1;
int whiteValue = -6000000;
PImage img;
String[] filenames;
int row = 0;
int column = 0;
int i = 0;
java.io.File folder = new java.io.File(dataPath(basedir));
java.io.FilenameFilter extfilter = new java.io.FilenameFilter() {
boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(fileext);
}
};
void setup() {
if (resumeprocess > 0) {i = resumeprocess - 1;frameCount = i;}
size(1920, 1080); // Resolution of the frames. It's likely there's a better way of doing this..
filenames = folder.list(extfilter);
}
void draw() {
if (i +1 > filenames.length) {println("Uh.. Done!"); System.exit(0);}
row = 0;
column = 0;
img = loadImage(basedir+"/"+filenames[i]);
image(img,0,0);
while(column < width-1) {
img.loadPixels();
sortColumn();
column++;
img.updatePixels();
}
while(row < height-1) {
img.loadPixels();
sortRow();
row++;
img.updatePixels();
}
image(img,0,0);
saveFrame(basedir+"/out/"+filenames[i]);
println("Frames processed: "+frameCount+"/"+filenames.length);
i++;
}
essentially I want to do the same thing only with a different image process but my code is not doing this to all with in the folder... just one file.
You seem to be confused about what the setup() function does. It runs once, and only once, at the beginning of your code's execution. You don't have any looping structure for processing the other files, so it's no wonder that it only processes the first one. Perhaps wrap the entire thing in a for loop? It looks like you kind of thought about this, judging by the global variable i, but you never increment it to go to the next image and you overwrite its value in several for loops later anyway.
I need a suggestion. I want to have a function that returns random numbers from let say 1 to 100, with condition to not repeat the chosen number. It is something like chess table that will be filled with something random and not one thing over another thing... If someone can tell a suggestion I'll be very happy. Thanks.
Create an Array of 100 numbers (1..100), then 'sort' the Array by 'random'. You can then pull out the numbers one at a time working your way through the array.
I haven't tested the code below but I had these snippets available that you could piece together to achieve the intended result.
public static function randomNumber(min:Number, max:Number):Number{
var rnd:Number = Math.floor((Math.random()*((max+1)-min))+min);
return rnd;
}
public static function randomize(arr:Array):Array{
var len:Number = arr.length;
var rnd:Number;
var tmp:Object;
for(var i:Number=0;i<len;i++){
rnd = randomNumber(0,(len-1));
tmp = arr[i];
arr[i] = arr[rnd];
arr[rnd] = tmp;
}
return arr;
}
var setOfNumbers:Array = new Array();
for(var i:int=0;i<100;i++){
setOfNumbers[i] = (i+1);
}
var shuffledSetOfNumbers:Array = randomize(setOfNumbers);
Notes:
For the purists this "randomizing" isn't "truly" random (if you're writing a Card shuffler for a Vegas gambling machine you'll want to use something different - case in point!)
My randomNumber and randomize functions above are static as I've typically included them that way in the apps I've needed them but you don't have to use it this way
My original lib used Number vs int or uint for some of the variables for more options when used but feel free to clean that up
also like that...
package
{
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* #author Vadym Gordiienko
*/
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var startArray:Array = generateNumberArray(100);
var randomArray:Array = randomArray(startArray);
trace("startArray = " + startArray);
trace("randomArray = " + randomArray);
}
/**
* generate Array of numbers by length
* #param length
* #return Array of numbers
*/
public static function generateNumberArray(length:int):Array
{
var numberArray:Array = [];
for (var i:int = 0; i < length; i++)
{
numberArray[i] = i+1;
}
return numberArray;
}
/**
* generate randomly mixed array by input array
* #param inputArray - simple not mixed array
* #return Array - mixed array
*/
public static function randomArray(inputArray:Array):Array
{
var randomArray:Array = [];
var tempArray:Array = [];
for (var i:int = 0; i < inputArray.length; i++)
{
tempArray.push(inputArray[i]);
}
while (tempArray.length)
{
var randomNumber:int = Math.round(Math.random() * (tempArray.length - 1));// get random number of left array
randomArray.push( tempArray[randomNumber] );
tempArray.splice(randomNumber, 1); // remove randomed element from temporary aarray
}
tempArray = null;
delete [tempArray];
return randomArray;
}
}
}
I am having a property which returns WriteableBitmap. when i am binding that property to the silverlight5 Image it showing the image, but when i am doing that in the WP it is not showing the image. when i am googling around this issue i saw that in WP the raw pixel values did not have alpha bits is set. But the same is working with silverlight. I don't know what is happening. Anybody have the similar issue or any round about?
(Imageproperty as WriteableBitmap).Invalidate();
<Image Source="{Binding Imageproperty}"/> (this is working in silverlight not in WP(7.1))
I had a similar sort of issue when trying to port some of the FaceLight code across from Silverlight to Windows Phone. The easiest way around this would be to manually set the Alpha value to 255 / opaque. So say if you had your WriteableBitmap that you wanted to display, result:
//convert to byte array
int stride = result.PixelWidth * 4; //brga32 is 32
int bytes = Math.Abs(stride) * result.PixelHeight;
byte[] data = result.ToByteArray();
int dataIndex = 0;
int nOffset = stride - result.PixelWidth * 4;
for (int y = 0; y < result.PixelHeight; ++y)
{
for (int x = 0; x < result.PixelWidth; ++x)
{
data[dataIndex + 3] = 0xFF; //set alpha to 255
dataIndex += 4; //skip to next pixel
}
dataIndex += nOffset;
}
WriteableBitmap finalImg = new WriteableBitmap(input.PixelWidth, input.PixelHeight);
return finalImg.FromByteArray(data);
Displaying the result from this method (the finalImg.FromByteArray(data) call) should display properly on the phone.
An alternative to this method above as well, is writing the WriteableBitmap to a .jpeg and then display the .jpeg instead - that seemed to work for me also but I didn't investigate that too thoroughly.
If the writeablebitmap has its pixeldata set or changed after the binding is established you need to call Invalidate to cause an update of the screen.
This goes for both Silverlight and Phone but you might have a race condition here that runs differently on both platforms.
I know it's an old post, but today I encountered the same problem on Windows Phone 8.1 Silverlight and I found nice solution, so I have decided to left it for people with similar problem. It was posted by Charles Petzold on MSDN as Video Feeds on Windows Phone 7 (it is shown on VideoSink class example, but it shouldn't be a problem to reproduce it with other case). He created a simple class that derives from VideoSink:
SimpleVideoSink C# code:
public class SimpleVideoSink : VideoSink
{
VideoFormat videoFormat;
WriteableBitmap writeableBitmap;
Action<WriteableBitmap> action;
public SimpleVideoSink(Action<WriteableBitmap> action)
{
this.action = action;
}
protected override void OnCaptureStarted() { }
protected override void OnCaptureStopped() { }
protected override void OnFormatChange(VideoFormat videoFormat)
{
this.videoFormat = videoFormat;
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
writeableBitmap = new WriteableBitmap(videoFormat.PixelWidth,
videoFormat.PixelHeight);
action(writeableBitmap);
});
}
protected override void OnSample(long sampleTimeInHundredNanoseconds,
long frameDurationInHundredNanoseconds, byte[] sampleData)
{
if (writeableBitmap == null)
return;
int baseIndex = 0;
for (int row = 0; row < writeableBitmap.PixelHeight; row++)
{
for (int col = 0; col < writeableBitmap.PixelWidth; col++)
{
int pixel = 0;
if (videoFormat.PixelFormat == PixelFormatType.Format8bppGrayscale)
{
byte grayShade = sampleData[baseIndex + col];
pixel = (int)grayShade | (grayShade << 8) |
(grayShade << 16) | (0xFF << 24);
}
else
{
int index = baseIndex + 4 * col;
pixel = (int)sampleData[index + 0] | (sampleData[index + 1] << 8) |
(sampleData[index + 2] << 16) | (sampleData[index + 3] << 24);
}
writeableBitmap.Pixels[row * writeableBitmap.PixelWidth + col] = pixel;
}
baseIndex += videoFormat.Stride;
}
writeableBitmap.Dispatcher.BeginInvoke(() =>
{
writeableBitmap.Invalidate();
});
}
}
However, this code needs some modification - VideoSink.CaptureSource must be provided with our CaptureSource (I just passed it into constructor):
public SimpleVideoSink(CaptureSource captureSource, Action<WriteableBitmap> action)
{
base.CaptureSource = captureSource;
this.action = action;
}
When we initialize SimpleVideoSink class in a ViewModel, we have to provide it an Action parameter. In my case it was enough to provide ViewModel with initialized field writeableBitmap:
ViewModel C# code:
private WriteableBitmap videoWriteableBitmap;
public WriteableBitmap VideoWriteableBitmap
{
get
{
return videoWriteableBitmap;
}
set
{
videoWriteableBitmap = value;
RaisePropertyChanged("VideoWriteableBitmap");
}
}
private void OnWriteableBitmapChange(WriteableBitmap writeableBitmap)
{
VideoWriteableBitmap = writeableBitmap;
}
//this part goes to constructor/method
SimpleVideoSink videoFrameHandler = new SimpleVideoSink(captureSource, OnWriteableBitmapChange);
Then all we have to do is to bind it to View:
View XAML code:
<Image Source="{Binding VideoWriteableBitmap}" />
In this example Image source is refreshed on every OnSample method invocation, and is dispatched to main thread through WriteableBitmap.Dispatcher.
This solution generates proper image with no blank pixel (alpha channel is also filled), and Invalidate() method works as it should.