Friday, March 20, 2015

Finding demon-possessed objects using your iPhone and poorly written software

A programming error in the upcoming video camera app for the iPhone, which will be equipped with the same image-processing filters shown on this blog, used for finding demons and related activity, inadvertently revealed a way to more easily discern between objects that are demon-possessed and otherwise.

With the filters, you can readily see which objects have demons by watching the chroma (or color noise or snow) on the display or in recorded video, and noting the objects from which it streams; however, if there is a lot of noise—or the video is shot in the dark (because it has to be, of course)—this wasn't always feasible.

While developing a night-vision filter to work with the new camera app, I discovered by mistake that, if only the portions of the camera's preview screen (or video) that are moving are redrawn while everything else stationary is not, the trails and streams of chroma will be the only thing moving. All the other random noise particles don't generate enough of a difference between stationary objects and moving ones to get noticed. By contrast, the giant blocks of chroma, pouring off of a demon in hiding make a substantial enough change by its motion and size that is even easier to see than with previous filters. This video demonstrates this quite well, showing the tell-tale EMF radiation emissions from the demon cloak emanating from a towel draped over a desk lamp:


As you can see, by retaining all non-moving pixels, and by only redrawing the moving ones, you can track the trail of focused chroma emissions (or streams)—a dead give-away to demons in possession of objects, who are trying to hide right in front of your face. Of course, you have to hold the camera very still, as when it's moved, everything blurs into long strands of stretched motion.

Although a bit like reading an old-time radar blip screen, the white blocks that represent chroma in the image dancing upwards and away from a towel draped over a desk lamp, a towel that months ago showed a demon inside it in a video still frame.

Demons hide in everything, everywhere
While demons hide in just about anything, anywhere [see Strangest things, places demons possess], they prefer messes [see Demonic Feng Shui]. In this image, there are at least half of dozen demon faces blended in the folds of the clothes and bedsheets strewn about the room:

They are difficult to see unless you're somewhat familiar with a wide-variety of demonic species, but the faces are recognizable as such even still
Here's the same image, with a hint to the location of the faces (all are facing profile):

Having trouble seeing them? That's why they call you a victim, but don't feel sorry for you
The demon in the following video clip is a little more obvious:


Don't know OpenGL ES 3.0?
Then use Core Image to do per-pixel processing on your iPhone:

#if TARGET_OS_IPHONE
#import <CoreImage/CoreImage.h>
#else
#import <QuartzCore/QuartzCore.h>
#endif

@interface CubicFunction : CIFilter
{
    CIImage *inputImage;
    NSNumber *inputA;
    NSNumber *inputB;
    NSNumber *inputC;
    NSNumber *inputD;
}
@property (retain, nonatomic) CIImage *inputImage;
@property (copy, nonatomic) NSNumber *inputA;
@property (copy, nonatomic) NSNumber *inputB;
@property (copy, nonatomic) NSNumber *inputC;
@property (copy, nonatomic) NSNumber *inputD;

@end

static const unsigned int minCubeSize = 2;
static const unsigned int maxCubeSize = 64;
static const unsigned int defaultCubeSize = 32;
static const float defaultA = 2.00;
static const float defaultB = 3.00;
static const float defaultC = -8.00;
static const float defaultD = 6.00;

typedef enum cubeOperation {
    
    cubeMakeTransparent = 0,
    
    cubeMakeGrayscale // this is "color accent" mode
    
} cubeOperation;


@implementation CubicFunction

@synthesize inputImage;
@synthesize inputA, inputB, inputC, inputD;

static void rgbToHSV(const float *rgb, float *hsv)
{
    float minV = MIN(rgb[0], MIN(rgb[1], rgb[2]));
    float maxV = MAX(rgb[0], MAX(rgb[1], rgb[2]));
    
    float chroma = maxV - minV;
    
    hsv[0] = hsv[1] = 0.0;
    hsv[2] = maxV;
    
    if ( maxV != 0.0 )
        hsv[1] = chroma / maxV;
    
    if ( hsv[1] != 0.0 )
    {
        if ( rgb[0] == maxV )
            hsv[0] = (rgb[1] - rgb[2])/chroma;
        else if ( rgb[1] == maxV )
            hsv[0] = 2.0 + (rgb[2] - rgb[0])/chroma;
        else
            hsv[0] = 4.0 + (rgb[0] - rgb[1])/chroma;
        
        hsv[0] /= 6.0;
        if ( hsv[0] < 0.0 )
            hsv[0] += 1.0;
    }
}

static void f(float *rgb)
{
    float a = 2.0;
    float b = 3.0;
    float c = -8.0;
    float d = 6.0;
    float x = MAX(rgb[0], MAX(rgb[1], rgb[2]));
    
    rgb[0] = rgb[1] = rgb[2] = pow(a * x, 3.0) + pow(b * x, 2.0) + pow(c * x, 2.0) + d; // ranges from 5, 5, 10, 25 to -5, -5, -10, -25; defaults 2, 3, -8, 6
}

static BOOL buildCubeData(NSMutableData *cubeData, unsigned int cubeSize, enum cubeOperation op)
{
    
    float a = 2.0;
    float b = 3.0;
    float c1 = -8.0;
    float d = 6.0;
    
    uint8_t *c = (uint8_t *)[cubeData mutableBytes];
    float *cFloat = (float *)c;
    
    BOOL useFloat = FALSE;
    
    size_t baseMultiplier = cubeSize * cubeSize * cubeSize * 4;
    
    if ( [cubeData length] == (baseMultiplier * sizeof(uint8_t)) )
        useFloat = FALSE;
    else if ( [cubeData length] == (baseMultiplier * sizeof(float)) )
        useFloat = TRUE;
    else
        return FALSE;
    
    for(int z = 0; z < cubeSize; z++) {
        float blueValue = pow(a * ((double)z)/(cubeSize-1), 3.0) + pow(b * ((double)z)/(cubeSize-1), 2.0) + pow(c1 * ((double)z)/(cubeSize-1), 2.0) + d; // ((double)z)/(cubeSize-1);
        for(int y = 0; y < cubeSize; y++) {
            float greenValue = pow(a * ((double)y)/(cubeSize-1), 3.0) + pow(b * ((double)y)/(cubeSize-1), 2.0) + pow(c1 * ((double)y)/(cubeSize-1), 2.0) + d; // ((double)y)/(cubeSize-1);
            for(int x = 0; x < cubeSize; x++) {
                float redValue = pow(a * ((double)x)/(cubeSize-1), 3.0) + pow(b * ((double)x)/(cubeSize-1), 2.0) + pow(c1 * ((double)x)/(cubeSize-1), 2.0) + d; // ((double)x)/(cubeSize-1);
                
                //float hsv[3] = { 0.0, 0.0, 0.0 };
                float rgb[3] = { redValue, greenValue, blueValue };
                
                //rgbToHSV(rgb, hsv);
                
                //f(rgb);
                
                // RGBA channel order.
                
                if ( useFloat ) {
                    *cFloat++ = rgb[0] * 1.0;
                    *cFloat++ = rgb[1] * 1.0;
                    *cFloat++ = rgb[2] * 1.0;
                    *cFloat++ = 1.0;
                } else {
                    *c++ = (uint8_t) (255.0 * rgb[0] * 1); //alphaValue);
                    *c++ = (uint8_t) (255.0 * rgb[1] * 1); // alphaValue);
                    *c++ = (uint8_t) (255.0 * rgb[2] * 1); //alphaValue);
                    *c++ = (uint8_t) (255.0 * 1.0);
                }
            }
        }
    }
    
    return TRUE;
}


+ (NSDictionary *)customAttributes
{
    
    return @{
             kCIAttributeFilterDisplayName :@"CubicFunction",
             
             kCIAttributeFilterCategories :
  @[kCICategoryColorEffect, kCICategoryVideo, kCICategoryInterlaced, kCICategoryNonSquarePixels, kCICategoryStillImage],
             
             @"inputA" :
  @{
                     kCIAttributeMin       : @-5.00,
                     kCIAttributeSliderMin : @-5.00,
                     kCIAttributeSliderMax : @5.00,
                     kCIAttributeMax       : @5.00,
                     kCIAttributeDefault   : @2.00,
                     kCIAttributeType      : kCIAttributeTypeScalar
                     },
             
             @"inputB" :
  @{
                     kCIAttributeMin       : @-5.00,
                     kCIAttributeSliderMin : @-5.00,
                     kCIAttributeSliderMax : @5.00,
                     kCIAttributeMax       : @5.00,
                     kCIAttributeDefault   : @3.00,
                     kCIAttributeType      : kCIAttributeTypeScalar
                     },
             
             @"inputC" :
  @{
                     kCIAttributeMin       : @-10.00,
                     kCIAttributeSliderMin : @-10.00,
                     kCIAttributeSliderMax : @10.00,
                     kCIAttributeMax       : @10.00,
                     kCIAttributeDefault   : @-8.00,
                     kCIAttributeType      : kCIAttributeTypeScalar
                     },
             
             @"inputD" :
  @{
                     kCIAttributeMin       : @-25.00,
                     kCIAttributeSliderMin : @-25.00,
                     kCIAttributeSliderMax : @25.00,
                     kCIAttributeMax       : @25.00,
                     kCIAttributeDefault   : @6.00,
                     kCIAttributeType      : kCIAttributeTypeScalar
                     },
             };
}

- (void)setDefaults
{
    self.inputA = @2.0;
    self.inputB = @3.0;
    self.inputC = @-8.0;
    self.inputD = @6.0;
}

- (CIImage *)outputImage
{
    CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
     
     const unsigned int cubeSize = MAX(MIN(64, maxCubeSize), minCubeSize);
     
     size_t baseMultiplier = cubeSize * cubeSize * cubeSize * 4;
     
     // you can use either uint8 data or float data by just setting this variable
     BOOL useFloat = FALSE;
     NSMutableData *cubeData = [NSMutableData dataWithLength:baseMultiplier * (useFloat ? sizeof(float) : sizeof(uint8_t))];
     
     if ( ! cubeData )
     return inputImage;
     
     if ( ! buildCubeData(cubeData, cubeSize, cubeMakeGrayscale) )
     return inputImage;
     
     // don't just use inputCubeSize directly because it is a float and we want to use an int.
     [colorCube setValue:[NSNumber numberWithInt:cubeSize] forKey:@"inputCubeDimension"];
     [colorCube setValue:cubeData forKey:@"inputCubeData"];
     [colorCube setValue:inputImage forKey:kCIInputImageKey];
     
     CIImage *outputImage = [colorCube valueForKey:kCIOutputImageKey];
     
     [colorCube setValue:nil forKey:@"inputCubeData"];
     [colorCube setValue:nil forKey:kCIInputImageKey];
     
     return outputImage;
}


@end