summaryrefslogtreecommitdiff
path: root/NT/src/cvimage.cpp
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2014-05-22 08:36:24 +0100
committerTim Redfern <tim@eclectronics.org>2014-05-22 08:36:24 +0100
commitbb6498e5ff6a8a8af8c06300dac051659a37e89b (patch)
tree873cd3f3eba85e38c12995b077ce0db9ee82afab /NT/src/cvimage.cpp
parentebc874413991fbc3d07493ece55f88f23e437af6 (diff)
NT figuring out type system
Diffstat (limited to 'NT/src/cvimage.cpp')
-rw-r--r--NT/src/cvimage.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/NT/src/cvimage.cpp b/NT/src/cvimage.cpp
new file mode 100644
index 0000000..b255848
--- /dev/null
+++ b/NT/src/cvimage.cpp
@@ -0,0 +1,252 @@
+#include "cvimage.h"
+
+using namespace std;
+
+namespace Rotor {
+ //space out to 32 bit RGB padding for cairo
+ void Image::convert24(){
+ cv::cvtColor(rgb,rgb, CV_RGBA2RGB);
+ }
+ void Image::convert32(){
+ cv::cvtColor(rgb,rgb, CV_RGB2RGBA);
+ }
+ Image & Image::operator+=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ rgb+=other.rgb;
+ }
+ return *this;
+ }
+ Image & Image::operator*=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ //rgb/=other.rgb; //does funny glitchy stuff
+ //could use cv::Mat.mul() here
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.multiply[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::operator^=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ rgb^=other.rgb;
+ }
+ return *this;
+ }
+ Image & Image::add_wrap(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //creates rainbow overload, openCV doesn't do this
+ rgb.data[i]=(unsigned char)(((int)other.rgb.data[i]+(int)rgb.data[i]));
+ }
+ }
+ return *this;
+ }
+ Image & Image::divide_wrap(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //creates rainbow overload, openCV doesn't do this
+ rgb/=other.rgb; //does funny glitchy stuff
+ }
+ }
+ return *this;
+ }
+ //THIS OPENCV VERSION IS SLOWER THAN THE OLDSKOOL VERSION BELOW
+ Image & Image::alpha_blend_cv(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else if (!other.alpha.data){
+ //default to full on alpha
+ rgb=other.rgb.clone();
+ }
+ else {
+ //overlay the other image based on its alpha values
+ //https://gist.github.com/Brick85/5009046 - this is a dumb way to do it?
+ //how to invert a matrix?
+ //'invert' is matrix invert - different
+ //subtract from a scalar (1) ?
+ vector<cv::Mat> ichans,ochans;
+ vector<cv::Mat> compchans;
+ cv::split(rgb,ichans);
+ cv::split(other.rgb,ochans);
+ uint8_t b=0xFF;
+ cv::Mat iA=b-other.alpha;
+ for (int i=0;i<3;i++) {
+ compchans.push_back(ichans[i].mul(iA,1.0/255.0)+ochans[i].mul(other.alpha,1.0/255.0));
+ }
+ merge(compchans,rgb);
+ //rgb+=other.rgb;
+ //for (int i=0;i<w*h*3;i++) {
+ // rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
+ //}
+ }
+
+ return *this;
+ }
+ Image & Image::alpha_blend(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else if (!other.alpha.data){
+ //default to full on alpha
+ rgb=other.rgb.clone();
+ }
+ else {
+ for (int i=0;i<w*h*3;i++) {
+ rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
+ }
+ }
+ return *this;
+ }
+ Image & Image::alpha_merge(const Image &other) {
+ //converts the incoming image to monochrome and inserts it into the alpha channel of this image
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ cv::cvtColor(other.rgb,alpha,CV_RGB2GRAY);
+ }
+ return *this;
+ }
+ Image & Image::alpha_from_cv(cv::Mat &other){
+ //if (other.w!=w||other.h!=h) {
+ // cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //}
+ //else {
+ if (other.channels()==1) {
+ alpha=other;
+ }
+ else cv::cvtColor(other,alpha,CV_RGB2GRAY);
+ //}
+ return *this;
+ }
+ Image & Image::overlay(const Image &other){
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot overlay images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else {
+ for (int i=0;i<h*w*3;i++) {
+ rgb.data[i]=pixels.overlay[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::min(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.min[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::max(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.max[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::operator=(const Image &other) {
+ //can be optimised? was trying to use other.data.clone()
+ if (setup(other.w,other.h)){
+ //for (int i=0;i<h*w*3;i++) {
+ // rgb.data[i]=other.rgb.data[i];
+ //}
+ memcpy(rgb.data,other.rgb.data,h*w*3); //saves ~2.4 ms copying a 640x360 image
+
+ }
+ return *this;
+ }
+ //channel rearrangement
+ //RGBAZ - these are channels 0-4
+ //HSB - can also have these virtual channels 5-7
+ //convert channels- int outChannel[5] - {0,1,2,-5,4} - this mapping sends inverted brightness to alpha
+
+ //scalar operations allocate a new image.
+ //maybe this could not be the case if the data is owned by this image?
+ //need to look into auto_ptr
+ Image & Image::operator*=(const double &amount) {
+ //cerr<<"amount: "<<amount<<endl;
+ //rgb*=amount;
+ uint8_t amt=(uint8_t)(amount*255.0);
+ for (int i=0;i<h*w*3;i++) {
+ rgb.data[i]=pixels.multiply[rgb.data[i]][amt];
+ }
+ //again this is faster
+ return *this;
+ }
+ Image & Image::operator+=(const double &amount) {
+ rgb+=(amount*255.0);
+ return *this;
+ }
+ Image & Image::operator-=(const double &amount) {
+ rgb-=(amount*255.0);
+ return *this;
+ }
+ Image & Image::operator/=(const double &amount) {
+ rgb/=amount;
+ return *this;
+ }
+ Image * Image::operator*(const double &amount) {
+ //LEAK!! even if the image is deleted!! opencv??
+ Image *other=new Image(w,h);
+ other->rgb=rgb*amount;
+ return other;
+ }
+ Image * Image::operator+(const double &amount) {
+ uint8_t amt=(uint8_t)(amount*255.0);
+ Image *other=new Image(w,h);
+ other->rgb=rgb+amt;
+ return other;
+ }
+ Image * Image::operator-(const double &amount) {
+ uint8_t amt=(uint8_t)(amount*255.0);
+ Image *other=new Image(w,h);
+ other->rgb=rgb-amt;
+ return other;
+ }
+ Image * Image::operator/(const double &amount) {
+ Image *other=new Image(w,h);
+ other->rgb=rgb/amount;
+ return other;
+ }
+ cv::Mat& Image::get_mipmap(int level){
+ if (mipmaps.find(level)!=mipmaps.end()) return mipmaps[level];
+ //levels start at 1
+ int nw=std::max(1.0,w/pow(2,level));
+ int nh=std::max(1.0,h/pow(2,level));
+ cv::Mat mip;;
+ cv::resize(rgb,mip,cv::Size(nw,nh),0,0,cv::INTER_AREA );
+ mipmaps[level]=mip;
+ return mipmaps[level];
+
+ }
+}