Inverting a bitmap in Embarcadero C++Builder - image

The same problem happens in Borland C++Builder 6 and Embarcadero C++Builder 2010.
When I try to invert an image, the form freezes for about 5 seconds and nothing happens. When I click again, the image is inverted within a blink of an eye, and again, again...
To reproduce, create a form with a TImage and two TButton's using this code:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <jpeg.hpp>
#pragma hdrstop
#pragma package(smart_init)
#pragma resource "*.dfm"
#include "Unit1.h"
TForm1 *Form1;
Graphics::TBitmap *CurrentBitmap;
bool bLoaded = false;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
CurrentBitmap = new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
bool __fastcall Invert( TImage *img ) {
if( bLoaded ) {
double Scale, ScaleW, ScaleH;
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->Assign( CurrentBitmap );
DWORD **pixel = new DWORD*[bmp->Height];
for( long y=0; y<bmp->Height; y++ ) {
pixel[y] = (DWORD*)(bmp->ScanLine[y]);
for( long x=0; x<bmp->Width; x++ ) {
if( pixel[y][x] == clBlack ) {
pixel[y][x] = clWhite;
} else if( pixel[y][x] == clWhite ) {
pixel[y][x] = clBlack;
}
}
}
delete[] pixel;
ScaleW = (double)bmp->Width / img->ClientWidth;
ScaleH = (double)bmp->Height / img->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
CurrentBitmap->Assign( bmp );
img->Picture->Bitmap->Canvas->StretchDraw(Rect(0, 0, bmp->Width/Scale, bmp->Height/Scale), bmp );
delete bmp;
return true;
} else {
return false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) {
TJPEGImage *jpg = new TJPEGImage();
jpg->LoadFromFile( "V:\\CBuilder\\BCB10\\GerberTest\\Testdata\\GerberTest.dpi2400.mskcmp.jpg" );
CurrentBitmap->Width = jpg->Width;
CurrentBitmap->Height = jpg->Height;
CurrentBitmap->Canvas->StretchDraw(Rect(0, 0, jpg->Width, jpg->Height), jpg );
bLoaded = true;
double Scale, ScaleW, ScaleH;
ScaleW = (double)jpg->Width / Image1->ClientWidth;
ScaleH = (double)jpg->Height / Image1->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
Image1->Canvas->StretchDraw(Rect(0, 0, jpg->Width/Scale, jpg->Height/Scale), jpg );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) {
Invert( Image1 );
}
I cannot explain why the application freezes, or what the code is doing during the 5 second delay.

Like Remy Lebeau mentioned you should set the PixelFormat. I tried your solution which did not seems to invert images properly. Below you find a solution which should work properly.
#include <JPEG.hpp>
Byte __fastcall IntToByte(int AValue)
{
if (AValue > 255)
return 255;
else if (AValue < 0)
return 0;
else
return AValue;
}
// ---------------------------------------------------------------------------
void __fastcall InvertBitmap(Graphics::TBitmap *ABitmap)
{
Byte *p0;
int red, green, blue;
for (int y = 0; y < ABitmap->Height; y++) {
p0 = (Byte*) ABitmap->ScanLine[y];
for (int x = 0; x < ABitmap->Width; x++) {
red = p0[x * 3];
green = p0[x * 3 + 1];
blue = p0[x * 3 + 2];
// invert
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
p0[x * 3] = IntToByte(red);
p0[x * 3 + 1] = IntToByte(green);
p0[x * 3 + 2] = IntToByte(blue);
}
}
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Screen->Cursor = crHourGlass;
TJPEGImage *jpeg = new TJPEGImage();
Graphics::TBitmap *bitmap = new Graphics::TBitmap();
try {
jpeg->LoadFromFile("**YOUR-JPEG-FILE**");
bitmap->SetSize(jpeg->Width, jpeg->Height);
bitmap->Canvas->Draw(0, 0, jpeg);
bitmap->PixelFormat = pf24bit;
InvertBitmap(bitmap);
Image1->Picture->Bitmap->Assign(bitmap);
}
__finally {
jpeg->Free();
bitmap->Free();
}
Screen->Cursor = crDefault;
}
// ---------------------------------------------------------------------------

Related

LVGL Compile error “dram0.bss’ will not fit in region `dram0_0_seg’” with ILI9488 & ESP32 on Arduino Core

I constantly get this error, no matter what I'm doing... I have an ILI9488 with 4-wire SPI and a GT911 capacitive Touch driver on an ESP32 (2MB, no PSRAM, arduino core).
this is my main.ino-file:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include "Goodix.h"
#define INT_PIN 26
#define RST_PIN 15
#define SDA_PIN 22
#define SCL_PIN 16
Goodix touch = Goodix();
#define DISPLAY_BUF_SIZE 480 * 10
static uint16_t display_widht = 480;
static uint16_t display_height = 320;
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
bool touched = false;
GTPoint touchDat;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ DISPLAY_BUF_SIZE];
lv_disp_drv_t disp_drv; //display driver
lv_indev_drv_t touch_drv; //touchpad driver
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ){
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.endWrite();
lv_disp_flush_ready( disp );
}
void handleTouch(int8_t contacts, GTPoint* points) {
Serial.printf("Contacts: %d\n", contacts);
if(contacts > 0) touched = true;
else touched = false;
for (uint8_t i = 0; i < contacts; i++) {
touchDat = points[0];
Serial.printf("C%d: %d %d \n", points[i].trackId, points[i].x, points[i].y);
}
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * touch_drv, lv_indev_data_t * data ){
if( !touched ) //kein Touch
{
data->state = LV_INDEV_STATE_REL;
}
else //touch!
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchDat.x;
data->point.y = touchDat.y;
}
}
void i2cInit(){
Wire.setPins(SDA_PIN, SCL_PIN);
Wire.setClock(400000);
Wire.begin();
delay(100);
}
void touchInit() {
touch.setHandler(handleTouch);
touch.setRes(display_widht, display_height);
touch.setRotation(3);
touch.begin(INT_PIN, RST_PIN, GOODIX_I2C_ADDR_28);
Serial.print("Check ACK on addr request on 0x");
Serial.print(touch.i2cAddr, HEX);
Wire.beginTransmission(touch.i2cAddr);
if (!Wire.endTransmission()) {
Serial.println(": SUCCESS");
} else {
Serial.print(": ERROR!");
}
}
void tftInit(){
tft.begin();
tft.setRotation(3);
lv_disp_draw_buf_init( &draw_buf, buf, NULL, DISPLAY_BUF_SIZE ); //init draw Buffer
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your display resolution*/
disp_drv.hor_res = display_widht;
disp_drv.ver_res = display_height;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the input device driver*/
static lv_indev_drv_t touch_drv;
lv_indev_drv_init( &touch_drv );
touch_drv.type = LV_INDEV_TYPE_POINTER;
touch_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &touch_drv );
//create simple label
lv_obj_t *label = lv_label_create( lv_scr_act() );
lv_label_set_text( label, "Hello World!!" );
lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
}
void setup() {
Serial.begin(115200); /* prepare for possible serial debug */
i2cInit();
touchInit(); //initialize touch
lv_init();
}
void loop() {
touch.loop();
lv_task_handler(); /* let the GUI do its work */
delay(5);
}
these are my main.ino and lv_config.h-files:
https://gist.github.com/kokospalme/a65448c1d10704066b9c6d2350c84a6d
even if I change LV_MEM_SIZE to something small like 1 or 10, I get the error, that " region `dram0_0_seg' overflowed by 22272 bytes". What am I doing wrong?

Error with the output of Camera Calibration OPENCV 3.2 with C++ Visual Studio 2015. Cant save output value

i am getting an error when using opencv camera calibration. When i debug my code, it just open the webcam not show the camera calibration value output in Folder Location.
i am using opencv 3.2 with VS 15
My code:
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/aruco.hpp"
#include "opencv2/calib3d.hpp"
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
const float calibrationSquareDimension = 0.01905f; //meters
const float arucoSquareDimension = 0.1016f; //meters
const Size chessboardDimensions = Size(9,6);
void createArucoMarkers()
{
Mat outputMarker;
Ptr<aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
for (int i = 0; i < 50; i++)
{
aruco::drawMarker(markerDictionary, i, 500, outputMarker, 1);
ostringstream convert;
string imageName = "4x4Marker_";
convert << imageName << i << ".jpg";
imwrite(convert.str(), outputMarker);
}
}
void createKnownBoardPosition(Size boardsize, float squareEdgeLength, vector<Point3f>& corners)
{
for (int i = 0; i < boardsize.height; i++)
{
for (int j = 0; j < boardsize.width; j++)
{
corners.push_back(Point3f(j * squareEdgeLength, i * squareEdgeLength, 0.0f));
}
}
}
void getchessboardcorners(vector<Mat> images, vector<vector<Point2f>>& allfoundcorners, bool showresults = false)
{
for (vector<Mat>::iterator iter = images.begin(); iter != images.end(); iter++)
{
vector<Point2f> pointBuf;
bool found = findChessboardCorners(*iter, Size(9, 6), pointBuf, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
if (found)
{
allfoundcorners.push_back(pointBuf);
}
if (showresults)
{
drawChessboardCorners(*iter, Size(9, 6), pointBuf, found);
imshow("Looking for Corners", *iter);
waitKey(0);
}
}
}
void cameraCalibration(vector<Mat> calibrationImages, Size boardSize, float squareEdgeLength, Mat& cameraMatrix, Mat& distanceCoefficients)
{
vector<vector<Point2f>> checkerboardImageSpacePoints;
getchessboardcorners(calibrationImages, checkerboardImageSpacePoints, false);
vector<vector<Point3f>> worldSpaceCornerPoints(1);
createKnownBoardPosition(boardSize, squareEdgeLength, worldSpaceCornerPoints[0]);
worldSpaceCornerPoints.resize(checkerboardImageSpacePoints.size(), worldSpaceCornerPoints[0]);
vector<Mat> rVectors, tVectors;
distanceCoefficients = Mat::zeros(8, 1, CV_64F);
calibrateCamera(worldSpaceCornerPoints, checkerboardImageSpacePoints, boardSize, cameraMatrix, distanceCoefficients, rVectors, tVectors );
}
bool saveCameraCalibration(string name, Mat cameraMatrix, Mat distanceCoefficients)
{
ofstream outStream(name);
if (outStream)
{
uint16_t rows = cameraMatrix.rows;
uint16_t columns = cameraMatrix.cols;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
double value = cameraMatrix.at<double>(r, c);
outStream << value << endl;
}
}
rows = distanceCoefficients.rows;
columns = distanceCoefficients.cols;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
double value = cameraMatrix.at<double>(r, c);
outStream << value << endl;
}
}
outStream.close();
return true;
}
return false;
}
int main(int argv, char** argc)
{
Mat frame;
Mat drawToFrame;
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
Mat distanceCoefficients;
vector<Mat> savedImages;
vector<vector<Point2f>> markerCorners, rejectedCandidates;
VideoCapture vid(0);
if (!vid.isOpened())
{
return 0;
}
int framesPersecond = 20;
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
while (true)
{
if (!vid.read(frame))
break;
vector<Vec2f> foundPoints;
bool found = false;
found = findChessboardCorners(frame, chessboardDimensions, foundPoints, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE );
frame.copyTo(drawToFrame);
drawChessboardCorners(drawToFrame, chessboardDimensions, foundPoints, found);
if (found)
imshow("Webcam", drawToFrame);
else
imshow("Webcam", frame);
char character = waitKey(1000 / framesPersecond);
switch (character)
{
case ' ':
//saving image
if(found)
{
Mat temp;
frame.copyTo(temp);
savedImages.push_back(temp);
}
break;
case 13:
//start calibration
if (savedImages.size() > 15)
{
cameraCalibration(savedImages, chessboardDimensions, calibrationSquareDimension, cameraMatrix, distanceCoefficients);
saveCameraCalibration("CameraCalibration", cameraMatrix, distanceCoefficients);
}
break;
case 27:
//exit
return 0;
break;
}
}
return 0;
}

ffmpeg avcodec_encode_video2 hangs when using Quick Sync h264_qsv encoder

When I use the mpeg4 or h264 encoders, I am able to successfully encode images to make a valid AVI file using the API for ffmpeg 3.1.0. However, when I use the Quick Sync encoder (h264_qsv), avcodec_encode_video2 will hang some of the time. I found that when using images that are 1920x1080, it was rare that avcodec_encode_video2 would hang. When using 256x256 images, it was very likely that the function would hang.
I have created the test code below that demonstrates the hang of avcodec_encode_video2. The code will create a 1000 frame, 256x256 AVI with a bit rate of 400000. The frames are simply allocated, so the output video should just be green frames.
The problem was observed using Windows 7 and Windows 10, using the 32-bit or 64-bit test application.
If anyone has any idea on how I can avoid the avcodec_encode_video2 hang I would be very grateful! Thanks in advance for any assistance.
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"
#include "avutil.h"
#include "imgutils.h"
#include "opt.h"
#include <rational.h>
}
#include <iostream>
// Globals
AVCodec* m_pCodec = NULL;
AVStream *m_pStream = NULL;
AVOutputFormat* m_pFormat = NULL;
AVFormatContext* m_pFormatContext = NULL;
AVCodecContext* m_pCodecContext = NULL;
AVFrame* m_pFrame = NULL;
int m_frameIndex;
// Output format
AVPixelFormat m_pixType = AV_PIX_FMT_NV12;
// Use for mpeg4
//AVPixelFormat m_pixType = AV_PIX_FMT_YUV420P;
// Output frame rate
int m_frameRate = 30;
// Output image dimensions
int m_imageWidth = 256;
int m_imageHeight = 256;
// Number of frames to export
int m_frameCount = 1000;
// Output file name
const char* m_fileName = "c:/test/test.avi";
// Output file type
const char* m_fileType = "AVI";
// Codec name used to encode
const char* m_encoderName = "h264_qsv";
// use for mpeg4
//const char* m_encoderName = "mpeg4";
// Target bit rate
int m_targetBitRate = 400000;
void addVideoStream()
{
m_pStream = avformat_new_stream( m_pFormatContext, m_pCodec );
m_pStream->id = m_pFormatContext->nb_streams - 1;
m_pStream->time_base = m_pCodecContext->time_base;
m_pStream->codec->pix_fmt = m_pixType;
m_pStream->codec->flags = m_pCodecContext->flags;
m_pStream->codec->width = m_pCodecContext->width;
m_pStream->codec->height = m_pCodecContext->height;
m_pStream->codec->time_base = m_pCodecContext->time_base;
m_pStream->codec->bit_rate = m_pCodecContext->bit_rate;
}
AVFrame* allocatePicture( enum AVPixelFormat pix_fmt, int width, int height )
{
AVFrame *frame;
frame = av_frame_alloc();
if ( !frame )
{
return NULL;
}
frame->format = pix_fmt;
frame->width = width;
frame->height = height;
int checkImage = av_image_alloc( frame->data, frame->linesize, width, height, pix_fmt, 32 );
if ( checkImage < 0 )
{
return NULL;
}
return frame;
}
bool initialize()
{
AVRational frameRate;
frameRate.den = m_frameRate;
frameRate.num = 1;
av_register_all();
m_pCodec = avcodec_find_encoder_by_name(m_encoderName);
if( !m_pCodec )
{
return false;
}
m_pCodecContext = avcodec_alloc_context3( m_pCodec );
m_pCodecContext->width = m_imageWidth;
m_pCodecContext->height = m_imageHeight;
m_pCodecContext->time_base = frameRate;
m_pCodecContext->gop_size = 0;
m_pCodecContext->pix_fmt = m_pixType;
m_pCodecContext->codec_id = m_pCodec->id;
m_pCodecContext->bit_rate = m_targetBitRate;
av_opt_set( m_pCodecContext->priv_data, "+CBR", "", 0 );
return true;
}
bool startExport()
{
m_frameIndex = 0;
char fakeFileName[512];
int checkAllocContext = avformat_alloc_output_context2( &m_pFormatContext, NULL, m_fileType, fakeFileName );
if ( checkAllocContext < 0 )
{
return false;
}
if ( !m_pFormatContext )
{
return false;
}
m_pFormat = m_pFormatContext->oformat;
if ( m_pFormat->video_codec != AV_CODEC_ID_NONE )
{
addVideoStream();
int checkOpen = avcodec_open2( m_pCodecContext, m_pCodec, NULL );
if ( checkOpen < 0 )
{
return false;
}
m_pFrame = allocatePicture( m_pCodecContext->pix_fmt, m_pCodecContext->width, m_pCodecContext->height );
if( !m_pFrame )
{
return false;
}
m_pFrame->pts = 0;
}
int checkOpen = avio_open( &m_pFormatContext->pb, m_fileName, AVIO_FLAG_WRITE );
if ( checkOpen < 0 )
{
return false;
}
av_dict_set( &(m_pFormatContext->metadata), "title", "QS Test", 0 );
int checkHeader = avformat_write_header( m_pFormatContext, NULL );
if ( checkHeader < 0 )
{
return false;
}
return true;
}
int processFrame( AVPacket& avPacket )
{
avPacket.stream_index = 0;
avPacket.pts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
avPacket.dts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
m_pFrame->pts++;
int retVal = av_interleaved_write_frame( m_pFormatContext, &avPacket );
return retVal;
}
bool exportFrame()
{
int success = 1;
int result = 0;
AVPacket avPacket;
av_init_packet( &avPacket );
avPacket.data = NULL;
avPacket.size = 0;
fflush(stdout);
std::cout << "Before avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
success = avcodec_encode_video2( m_pCodecContext, &avPacket, m_pFrame, &result );
std::cout << "After avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
if( result )
{
success = processFrame( avPacket );
}
av_packet_unref( &avPacket );
m_frameIndex++;
return ( success == 0 );
}
void endExport()
{
int result = 0;
int success = 0;
if (m_pFrame)
{
while ( success == 0 )
{
AVPacket avPacket;
av_init_packet( &avPacket );
avPacket.data = NULL;
avPacket.size = 0;
fflush(stdout);
success = avcodec_encode_video2( m_pCodecContext, &avPacket, NULL, &result );
if( result )
{
success = processFrame( avPacket );
}
av_packet_unref( &avPacket );
if (!result)
{
break;
}
}
}
if (m_pFormatContext)
{
av_write_trailer( m_pFormatContext );
if( m_pFrame )
{
av_frame_free( &m_pFrame );
}
avio_closep( &m_pFormatContext->pb );
avformat_free_context( m_pFormatContext );
m_pFormatContext = NULL;
}
}
void cleanup()
{
if( m_pFrame || m_pCodecContext )
{
if( m_pFrame )
{
av_frame_free( &m_pFrame );
}
if( m_pCodecContext )
{
avcodec_close( m_pCodecContext );
av_free( m_pCodecContext );
}
}
}
int main()
{
bool success = true;
if (initialize())
{
if (startExport())
{
for (int loop = 0; loop < m_frameCount; loop++)
{
if (!exportFrame())
{
std::cout << "Failed to export frame\n";
success = false;
break;
}
}
endExport();
}
else
{
std::cout << "Failed to start export\n";
success = false;
}
cleanup();
}
else
{
std::cout << "Failed to initialize export\n";
success = false;
}
if (success)
{
std::cout << "Successfully exported file\n";
}
return 1;
}
The problem no longer occurs now that I have updated to the latest Intel® Graphics Driver (version 15.45.10.4542)

How to debug "ArrayIndexOutOfBoundsException: 0" in Processing

I'm trying to make Kim Asendorf's pixel sorting code work with input from a webcam in processing.
I get the error: "ArrayIndexOutOfBoundsException: 0". Any ideas of how I can fix this?
//BLACK
int getFirstNotBlackY(int _x, int _y) {
int x = _x;
int y = _y;
color c;
if (y < height) {
while ( (c = cam.pixels[x + y * cam.width]) < blackValue) {
y++;
if (y >= height) return -1;
}
import processing.video.*;
Capture cam;
String[] cameras = Capture.list();
int mode = 0;
//MODE:
//0 -> black
//1 -> bright
//2 -> white
//b(16777216)
int loops = 1;
int blackValue = -10000000;
int brigthnessValue = 60;
int whiteValue = -6000000;
int row = 0;
int column =
boolean saved = false;
void setup() {
size(640, 480);
import processing.video.*;
String[] cameras = Capture.list();
import processing.video.*;
if (cameras.length == 0) {
println("There are no cameras available for capture.");
exit();
} else {
println("Available cameras:");
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}
// The camera can be initialized directly using an
// element from the array returned by list():
cam = new Capture(this, cameras[0]);
cam.start();
}
}
I've added the code I'm using to initialize the webcam.

Video Delay/Buffer in Processing 2.0

I'm having a ton of trouble making a simple video delay in processing. I looked around on the internet and I keep finding the same bit of code and I can't get it to work at all. When I first tried it, it did nothing (at all). Here's my modified version (which at least seems to load frames into the buffer), I really have no idea why it doesn't work and I'm getting really tired of pulling out my hair. Please... please, for the love of god, please somebody point out the stupid mistake I'm making here.
And now, without further delay (hah, get it?), the code:
import processing.video.*;
VideoBuffer vb;
Movie myMovie;
Capture cam;
float seconds = 1;
void setup() {
size(320,240, P3D);
frameRate(30);
String[] cameras = Capture.list();
if (cameras.length == 0) {
println("There are no cameras available for capture.");
exit();
} else {
println("Available cameras:");
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}
cam = new Capture(this, cameras[3]);
cam.start();
}
vb = new VideoBuffer(90, width, height);
}
void draw() {
if (cam.available() == true) {
cam.read();
vb.addFrame(cam);
}
image(cam, 0, 0);
image( vb.getFrame(), 150, 0 );
}
class VideoBuffer
{
PImage[] buffer;
int inputFrame = 0;
int outputFrame = 0;
int frameWidth = 0;
int frameHeight = 0;
VideoBuffer( int frames, int vWidth, int vHeight )
{
buffer = new PImage[frames];
for(int i = 0; i < frames; i++)
{
this.buffer[i] = new PImage(vWidth, vHeight);
}
this.inputFrame = 0;
this.outputFrame = 1;
this.frameWidth = vWidth;
this.frameHeight = vHeight;
}
// return the current "playback" frame.
PImage getFrame()
{
return this.buffer[this.outputFrame];
}
// Add a new frame to the buffer.
void addFrame( PImage frame )
{
// copy the new frame into the buffer.
this.buffer[this.inputFrame] = frame;
// advance the input and output indexes
this.inputFrame++;
this.outputFrame++;
println(this.inputFrame + " " + this.outputFrame);
// wrap the values..
if(this.inputFrame >= this.buffer.length)
{
this.inputFrame = 0;
}
if(this.outputFrame >= this.buffer.length)
{
this.outputFrame = 0;
}
}
}
This works in Processing 2.0.1.
import processing.video.*;
Capture cam;
PImage[] buffer;
int w = 640;
int h = 360;
int nFrames = 60;
int iWrite = 0, iRead = 1;
void setup(){
size(w, h);
cam = new Capture(this, w, h);
cam.start();
buffer = new PImage[nFrames];
}
void draw() {
if(cam.available()) {
cam.read();
buffer[iWrite] = cam.get();
if(buffer[iRead] != null){
image(buffer[iRead], 0, 0);
}
iWrite++;
iRead++;
if(iRead >= nFrames-1){
iRead = 0;
}
if(iWrite >= nFrames-1){
iWrite = 0;
}
}
}
There is a problem inside your addFrame-Method. You just store a reference to the PImage object, whose pixels get overwritten all the time. You have to use buffer[inputFrame] = frame.get() instead of buffer[inputFrame] = frame. The get() method returns a copy of the image.

Resources