Browse Source

Kickoff

master
Felix 4 years ago
parent
commit
0ee172bd5b
  1. 13
      LICENSE
  2. 32
      Makefile
  3. 238
      infragram.cpp
  4. 209
      jpeg.hpp

13
LICENSE

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Felix Niederwanger <felix@feldspaten.org>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

32
Makefile

@ -0,0 +1,32 @@
# Default compiler and compiler flags
CXX=g++
CC=gcc
# Default flags for all compilers
O_FLAGS=-O3 -Wall -Wextra -pedantic
# Debugging flags
#O_FLAGS=-Og -g2 -Wall -Wextra -pedantic
CXX_FLAGS=$(O_FLAGS) -std=c++11
CC_FLAGS=$(O_FLAGS) -std=c99
# Binaries, object files, libraries and stuff
LIBS=-ljpeg
INCLUDE=
OBJS=
BINS=infragram
# Default generic instructions
default: all
all: $(OBJS) $(BINS)
clean:
rm -f *.o
# Object files
%.o: %.cpp %.hpp
$(CXX) $(CXX_FLAGS) -c $(INCLUDE) -o $@ $< $(LIBS)
infragram: infragram.cpp jpeg.hpp
$(CXX) $(CXX_FLAGS) $(INCLUDE) -o $@ $< $(LIBS)

238
infragram.cpp

@ -0,0 +1,238 @@
/** 2018, Felix Niederwanger
* This is my infragram code for taking pictures coming from the infragram camera
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/v4l2-common.h>
#include <linux/v4l2-controls.h>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <fstream>
#include <string>
// Jpeg reading routines
#include "jpeg.hpp"
using namespace std;
// This part is based on https://gist.github.com/mike168m/6dd4eb42b2ec906e064d
static int read_video(const char* device, int width, int height, const char* jpg_filename) {
int fd; // A file descriptor to the video device
fd = open(device, O_RDWR);
if(fd < 0)
return -1;
// 2. Ask the device if it can capture frames
v4l2_capability capability;
if(ioctl(fd, VIDIOC_QUERYCAP, &capability) < 0){
// something went wrong... exit
cerr << "Failed to get device capabilities, VIDIOC_QUERYCAP" << endl;
close(fd);
return -2;
}
// 3. Set Image format
v4l2_format imageFormat;
imageFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
imageFormat.fmt.pix.width = width;
imageFormat.fmt.pix.height = height;
imageFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //V4L2_PIX_FMT_DV
imageFormat.fmt.pix.field = V4L2_FIELD_NONE;
// tell the device you are using this format
if(ioctl(fd, VIDIOC_S_FMT, &imageFormat) < 0){
cerr << "Device could not set format, VIDIOC_S_FMT" << endl;
close(fd);
return -3;
}
// 4. Request Buffers from the device
v4l2_requestbuffers requestBuffer = {0};
requestBuffer.count = 1; // one request buffer
requestBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // request a buffer wich we an use for capturing frames
requestBuffer.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_REQBUFS, &requestBuffer) < 0){
cerr << "Could not request buffer from device, VIDIOC_REQBUFS" << endl;
close(fd);
return -4;
}
// 5. Quety the buffer to get raw data ie. ask for the you requested buffer
// and allocate memory for it
v4l2_buffer queryBuffer = {0};
queryBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
queryBuffer.memory = V4L2_MEMORY_MMAP;
queryBuffer.index = 0;
if(ioctl(fd, VIDIOC_QUERYBUF, &queryBuffer) < 0){
cerr << "Device did not return the buffer information, VIDIOC_QUERYBUF" << endl;
close(fd);
return -5;
}
// use a pointer to point to the newly created buffer
// mmap() will map the memory address of the device to
// an address in memory
char* buffer = (char*)mmap(NULL, queryBuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, queryBuffer.m.offset);
memset(buffer, 0, queryBuffer.length);
// 6. Get a frame
// Create a new buffer type so the device knows whichbuffer we are talking about
v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = 0;
// Activate streaming
int type = bufferinfo.type;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0){
cerr << "Could not start streaming, VIDIOC_STREAMON" << endl;
close(fd);
return -6;
}
/***************************** Begin looping here *********************/
// Queue the buffer
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0){
cerr << "Could not queue buffer, VIDIOC_QBUF" << endl;
close(fd);
return -7;
}
// Dequeue the buffer
if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0){
cerr << "Could not dequeue the buffer, VIDIOC_DQBUF" << endl;
close(fd);
return -8;
}
// Frames get written after dequeuing the buffer
//cout << "Buffer has: " << (double)bufferinfo.bytesused / 1024 << " KBytes of data" << endl;
// Write the data out to file
ofstream outFile;
outFile.open(jpg_filename, ios::binary| ios::app);
int bufPos = 0, outFileMemBlockSize = 0; // the position in the buffer and the amoun to copy from
// the buffer
int remainingBufferSize = bufferinfo.bytesused; // the remaining buffer size, is decremented by
// memBlockSize amount on each loop so we do not overwrite the buffer
char* outFileMemBlock = NULL; // a pointer to a new memory block
int itr = 0; // counts thenumber of iterations
while(remainingBufferSize > 0) {
bufPos += outFileMemBlockSize; // increment the buffer pointer on each loop
// initialise bufPos before outFileMemBlockSize so we can start
// at the begining of the buffer
outFileMemBlockSize = 1024; // set the output block size to a preferable size. 1024 :)
outFileMemBlock = new char[sizeof(char) * outFileMemBlockSize];
// copy 1024 bytes of data starting from buffer+bufPos
memcpy(outFileMemBlock, buffer+bufPos, outFileMemBlockSize);
outFile.write(outFileMemBlock,outFileMemBlockSize);
// calculate the amount of memory left to read
// if the memory block size is greater than the remaining
// amount of data we have to copy
if(outFileMemBlockSize > remainingBufferSize)
outFileMemBlockSize = remainingBufferSize;
// subtract the amount of data we have to copy
// from the remaining buffer size
remainingBufferSize -= outFileMemBlockSize;
// display the remaining buffer size
//cout << itr++ << " Remaining bytes: "<< remainingBufferSize << endl;
}
// Close the file
outFile.close();
/******************************** end looping here **********************/
// end streaming
if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0){
cerr << "Could not end streaming, VIDIOC_STREAMOFF" << endl;
close(fd);
return -9;
}
close(fd);
return 0;
}
int main() {
const char* device = "/dev/video0";
const char* filename = "webcam_output.jpeg";
::unlink(filename);
int ret = read_video(device, 1900, 600, filename);
if(ret != 0) {
cerr << "Error reading from camera: (" << ret << ") - " << strerror(errno) << endl;
return EXIT_FAILURE;
}
cout << "Image received - saved to " << filename << endl;
try {
Jpeg jpeg(filename);
// Processing image using NDVI analysis
// Infragram: red channel = infrared, blue channel = visible
// NDVI = (IR-RGB)/(IR+RGB) where IR is the near IR and RGB is the visible light
// So for each pixel we are doing (R-B)/(R+B)
const int width = jpeg.width;
const int height= jpeg.height;
Jpeg dest(width, height);
for(int x=0;x<width;x++) {
for(int y=0;y<height;y++) {
rgb_t rgb = jpeg.rgb(x,y);
const unsigned char ir = rgb.r;
const unsigned char vis = rgb.b;
const float ndvi = (float)(ir-vis)/(float)(ir+vis);
//cout << (int)ir << '\t' << (int)vis << '\t' << ndvi << endl;
unsigned char x = (unsigned char)(ndvi * 255.0);
if(x > 255) x = 255;
//rgb.r = x; rgb.g = x; rgb.b = x;
dest.set(x,y, rgb);
}
}
::unlink("output.jpeg");
dest.write("output.jpeg");
cout << "NDVI written to 'output.jpeg'" << endl;
} catch (const char* err) {
cerr << "Error processing image: " << err << endl;
return EXIT_FAILURE;
}
// Now we need to read
return EXIT_SUCCESS;
}

209
jpeg.hpp

@ -0,0 +1,209 @@
/* 2018, Felix Niederwanger
* This is my own libjpeg wrapper
* Do not mind the crappy quality
*/
#include <stdio.h>
#include <unistd.h>
#include <jpeglib.h>
#include <string.h>
#include <errno.h>
#include <iostream>
struct {
unsigned char r;
unsigned char g;
unsigned char b;
} typedef rgb_t;
class Jpeg {
public:
int width = 0;
int height = 0;
int depth = 0;
private:
unsigned char *bmap = NULL;
public:
Jpeg(const Jpeg &src) {
this->width = src.width;
this->height = src.height;
this->depth = src.depth;
const size_t size = 3*width*height;
this->bmap = new unsigned char[size];
memcpy(this->bmap, src.bmap, sizeof(unsigned char)*size);
}
Jpeg(const int width, const int height) {
this->width = width;
this->height = height;
this->depth = 32;
const size_t size = 3*width*height;
this->bmap = new unsigned char[size];
bzero(this->bmap, sizeof(unsigned char)*size);
}
Jpeg(const char *filename) {
unsigned char r, g, b;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * infile; /* source file */
JSAMPARRAY pJpegBuffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
if ((infile = fopen(filename, "rb")) == NULL) {
throw "Error opening jpeg file";
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void) jpeg_read_header(&cinfo, TRUE);
(void) jpeg_start_decompress(&cinfo);
width = cinfo.output_width;
height = cinfo.output_height;
unsigned char * pDummy = new unsigned char [width*height*3];
unsigned char * pTest = pDummy;
if (!pDummy) {
throw "Out of memory";
}
row_stride = width * cinfo.output_components;
pJpegBuffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, pJpegBuffer, 1);
for (int x = 0; x < width; x++) {
r = pJpegBuffer[0][cinfo.output_components * x];
if (cinfo.output_components > 2) {
g = pJpegBuffer[0][cinfo.output_components * x + 1];
b = pJpegBuffer[0][cinfo.output_components * x + 2];
} else {
g = r;
b = r;
}
*(pDummy++) = r;
*(pDummy++) = g;
*(pDummy++) = b;
}
}
fclose(infile);
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
bmap = (unsigned char*)pTest;
depth = 32;
}
void write(const char* filename, int quality=100) {
FILE *ofp;
struct jpeg_compress_struct cinfo; /* JPEG compression struct */
struct jpeg_error_mgr jerr; /* JPEG error handler */
JSAMPROW row_pointer[1]; /* output row buffer */
int row_stride; /* physical row width in output buf */
if ((ofp = fopen(filename, "wb")) == NULL)
throw "Error opening file";
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, ofp);
cinfo.image_width = this->width;
cinfo.image_height = this->height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, 0);
jpeg_start_compress(&cinfo, TRUE);
/* Calculate the size of a row in the image */
row_stride = cinfo.image_width * cinfo.input_components;
/* compress the JPEG, one scanline at a time into the buffer */
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &(bmap[(this->height - cinfo.next_scanline - 1)*row_stride]);
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(ofp);
// Everything good so far :-)
}
virtual ~Jpeg() {
if(this->bmap != NULL) {
delete[] this->bmap;
this->bmap = NULL;
}
}
rgb_t operator()(int x, int y) {
return this->rgb(x,y);
}
rgb_t rgb(int x, int y) {
//if(bmap == NULL) throw "No data";
rgb_t ret;
const size_t index = 3*(width*y + x);
ret.r = this->bmap[index];
ret.g = this->bmap[index+1];
ret.b = this->bmap[index+2];
return ret;
}
/** Set pixel */
void set(int x, int y, rgb_t rgb) {
const size_t index = 3*(width*y + x);
this->bmap[index ] = rgb.r;
this->bmap[index+1] = rgb.g;
this->bmap[index+2] = rgb.b;
}
};
#if 0
using namespace std;
int main() {
try {
Jpeg jpeg("webcam_output.jpeg");
cout << "image read (" << jpeg.width << "x" << jpeg.height << ")" << endl;
rgb_t rgb;
rgb = jpeg(0,0);
cout << "(0,0) = " << (int)rgb.r << ',' << (int)rgb.g << ',' << (int)rgb.b << endl;
rgb = jpeg(0,1);
cout << "(0,1) = " << (int)rgb.r << ',' << (int)rgb.g << ',' << (int)rgb.b << endl;
rgb = jpeg(1,0);
cout << "(1,0) = " << (int)rgb.r << ',' << (int)rgb.g << ',' << (int)rgb.b << endl;
rgb = jpeg(1,1);
cout << "(1,1) = " << (int)rgb.r << ',' << (int)rgb.g << ',' << (int)rgb.b << endl;
rgb = jpeg(824,432);
cout << "(824,432) = " << (int)rgb.r << ',' << (int)rgb.g << ',' << (int)rgb.b << endl;
} catch (const char* msg) {
cerr << "Error: " << msg << endl;
return EXIT_FAILURE;
} catch (...) {
cerr << "Unknown error" << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#endif
Loading…
Cancel
Save