绘制直方图在iPhone中需要更高的精度

时间:2022-05-05 13:31:07

I am working in an app in which I need to draw Histogram of any inputed image. I can draw Histogram successfully but its not so sharp as its in PREVIEW in Mac OS.

我正在一个应用程序中工作,我需要绘制任何输入图像的直方图。我可以成功绘制直方图,但它不像Mac OS中的PREVIEW那样清晰。

As code is too large ,I have uploaded it to GitHub Click here to Download

由于代码太大,我已将其上传到GitHub点击此处下载

The RGB Values are read in

读入RGB值

  -(void)readImage:(UIImage*)image
{
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    for (int yy=0;yy<height; yy++)
    {
        for (int xx=0; xx<width; xx++)
        {
            // Now your rawData contains the image data in the RGBA8888 pixel format.
            int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
            for (int ii = 0 ; ii < 1 ; ++ii)
            {
                CGFloat red   = (rawData[byteIndex]     * 1.0) ;
                CGFloat green = (rawData[byteIndex + 1] * 1.0) ;
                CGFloat blue  = (rawData[byteIndex + 2] * 1.0) ;
                // CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
                byteIndex += 4;

                // TYPE CASTING ABOVE FLOAT VALUES TO THAT THEY CAN BE MATCHED WITH ARRAY'S INDEX.

                int redValue = (int)red;
                int greenValue = (int)green;
                int blueValue = (int)blue;


                // THESE COUNTERS COUNT " TOTAL NUMBER OF PIXELS " FOR THAT  Red , Green or Blue Value IN ENTIRE IMAGE.

                fltR[redValue]++;
                fltG[greenValue]++;
                fltB[blueValue]++;                
            }
        }
    }
    [self makeArrays];
    free(rawData);
}

I stored values in c array variables , fltR,fltG,fltB.

我将值存储在c数组变量fltR,fltG,fltB中。

I have a class ClsDrawPoint it has members

我有一个类ClsDrawPoint它有成员

@property CGFloat x;
@property CGFloat y;

Then prepared an array containing objects of ClsDrawPoint having fltR[]'s index as X value and value for that index as Y value .

然后准备一个包含ClsDrawPoint对象的数组,其中fltR []的索引为X值,该索引的值为Y值。

array is prepared and graph is drawn in

准备好数组并绘制图形

-(void)makeArrays

method

You may see the result

你可能会看到结果

绘制直方图在iPhone中需要更高的精度

Currently its not so accurate as it is in PREVIEW in mac for the same image. You can open an image in PREVIEW app in Mac and in Tools>AdjustColor , you will be able to see the Histogram of that image. I think if my graph is accrate , it will be sharper. Kindly check my code and suggest me if you find anyway to make it more accurate.

目前它不像在用于相同图像的预览中那样准确。您可以在Mac中的PREVIEW应用程序中打开图像,在工具> AdjustColor中,您将能够看到该图像的直方图。我认为如果我的图表是有效的,它会更清晰。请检查我的代码并建议我,如果你发现无论如何要使它更准确。

1 个解决方案

#1


4  

I pulled your sample down from Github and found that your drawRect: method in ClsDraw is drawing lines that are one pixel wide. Strokes are centered on the line, and with a width of 1, the stroke is split into half-pixels which introduces anti-aliasing.

我从Github上取下你的样本,发现你在ClsDraw中的drawRect:方法是绘制一个像素宽的线条。笔划以线为中心,宽度为1时,笔划被分成半像素,这会引入抗锯齿。

I moved your horizontal offsets by a half-pixel and rendering looks sharp. I didn't mess with vertical offsets, but to make them sharp you would need to round them and then move them to a half-pixel offset as well. I only made the following change:

我将水平偏移移动了半个像素,渲染看起来很清晰。我没有弄乱垂直偏移,但要使它们锐利,你需要将它们四舍五入,然后将它们移动到半像素偏移。我只做了以下改动:

#define OFFSET_X 0.5

- (void)drawRect:(CGRect)rect
{   
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  if ([arrPoints count] > 0)
  {
    CGContextSetLineWidth(ctx, 1);
    CGContextSetStrokeColorWithColor(ctx, graphColor.CGColor);
    CGContextSetAlpha(ctx, 0.8);
    ClsDrawPoint *objPoint;
    CGContextBeginPath(ctx);

    for (int i = 0 ; i < [arrPoints count] ; i++)
    {
      objPoint = [arrPoints objectAtIndex:i];
      CGPoint adjustedPoint = CGPointMake(objPoint.x+OFFSET_X, objPoint.y);
      CGContextMoveToPoint(ctx, adjustedPoint.x, 0);
      CGContextSetLineCap(ctx, kCGLineCapRound);
      CGContextSetLineJoin(ctx, kCGLineJoinRound);
      CGContextAddLineToPoint(ctx, adjustedPoint.x, adjustedPoint.y);
      CGContextMoveToPoint(ctx, adjustedPoint.x, adjustedPoint.y);
      CGContextStrokePath(ctx);
    }
  }
}

Notice the new OFFSET_X and the introduction of adjustedPoint.

注意新的OFFSET_X和adjustPoint的介绍。

You might also consider using a CGPoint stuffed into an NSValue instance for your points instead of your custom class ClsDrawPoint, unless you plan to add some additional behavior or properties. More details available here.

除非您计划添加一些其他行为或属性,否则您可能还会考虑使用填充到NSValue实例中的CGPoint代替您的自定义类ClsDrawPoint。更多细节在这里。

#1


4  

I pulled your sample down from Github and found that your drawRect: method in ClsDraw is drawing lines that are one pixel wide. Strokes are centered on the line, and with a width of 1, the stroke is split into half-pixels which introduces anti-aliasing.

我从Github上取下你的样本,发现你在ClsDraw中的drawRect:方法是绘制一个像素宽的线条。笔划以线为中心,宽度为1时,笔划被分成半像素,这会引入抗锯齿。

I moved your horizontal offsets by a half-pixel and rendering looks sharp. I didn't mess with vertical offsets, but to make them sharp you would need to round them and then move them to a half-pixel offset as well. I only made the following change:

我将水平偏移移动了半个像素,渲染看起来很清晰。我没有弄乱垂直偏移,但要使它们锐利,你需要将它们四舍五入,然后将它们移动到半像素偏移。我只做了以下改动:

#define OFFSET_X 0.5

- (void)drawRect:(CGRect)rect
{   
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  if ([arrPoints count] > 0)
  {
    CGContextSetLineWidth(ctx, 1);
    CGContextSetStrokeColorWithColor(ctx, graphColor.CGColor);
    CGContextSetAlpha(ctx, 0.8);
    ClsDrawPoint *objPoint;
    CGContextBeginPath(ctx);

    for (int i = 0 ; i < [arrPoints count] ; i++)
    {
      objPoint = [arrPoints objectAtIndex:i];
      CGPoint adjustedPoint = CGPointMake(objPoint.x+OFFSET_X, objPoint.y);
      CGContextMoveToPoint(ctx, adjustedPoint.x, 0);
      CGContextSetLineCap(ctx, kCGLineCapRound);
      CGContextSetLineJoin(ctx, kCGLineJoinRound);
      CGContextAddLineToPoint(ctx, adjustedPoint.x, adjustedPoint.y);
      CGContextMoveToPoint(ctx, adjustedPoint.x, adjustedPoint.y);
      CGContextStrokePath(ctx);
    }
  }
}

Notice the new OFFSET_X and the introduction of adjustedPoint.

注意新的OFFSET_X和adjustPoint的介绍。

You might also consider using a CGPoint stuffed into an NSValue instance for your points instead of your custom class ClsDrawPoint, unless you plan to add some additional behavior or properties. More details available here.

除非您计划添加一些其他行为或属性,否则您可能还会考虑使用填充到NSValue实例中的CGPoint代替您的自定义类ClsDrawPoint。更多细节在这里。